static/app/components/core/patterns/render-to-html.mdx
Some third-party libraries accept HTML strings instead of React elements. The most common case in Sentry is eCharts, whose tooltip formatter expects a callback that returns an HTML string. useRenderToString bridges this gap using the technique recommended by React for removing renderToString from client code.
import {useRenderToString} from '@sentry/scraps/renderToString';
function useMyTooltipFormatter() {
const renderToString = useRenderToString();
return useCallback(
(params: TooltipComponentFormatterCallbackParams) => {
return renderToString(<MyTooltip params={params} />);
},
[renderToString]
);
}
useRenderToString is a hook that returns a (tree: ReactNode) => string function. It automatically wraps the tree in a ThemeProvider so Emotion styles and theme tokens resolve correctly.
renderToString.This is the most common pattern. Create a custom hook that returns a formatter function.
import {useCallback} from 'react';
import type {TooltipComponentFormatterCallbackParams} from 'echarts';
import {Flex} from '@sentry/scraps/layout';
import {useRenderToString} from '@sentry/scraps/renderToString';
import {Text} from '@sentry/scraps/text';
export function useMyChartTooltipFormatter() {
const renderToString = useRenderToString();
return useCallback(
(params: TooltipComponentFormatterCallbackParams) => {
const data = Array.isArray(params) ? params[0] : params;
if (!data) {
return '';
}
return renderToString(
<Flex direction="column" gap="sm">
<Text bold>{data.name}</Text>
<Text variant="muted">{data.value}</Text>
</Flex>
);
},
[renderToString]
);
}
Then pass the formatter to your eCharts option:
function MyChart() {
const formatTooltip = useMyChartTooltipFormatter();
const option = {
tooltip: {
formatter: formatTooltip,
},
// ...
};
return <ReactEchartsCore option={option} />;
}
useCallback with [renderToString] in the dependency array. The renderToString function is stable as long as the theme doesn't change, so memoization works well here.renderToString. The theme provider is wired up, so Text, Flex, Container, and other scraps primitives work as expected.