Back to Sentry

Render to HTML

static/app/components/core/patterns/render-to-html.mdx

26.5.13.3 KB
Original Source

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.

API

tsx
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.

When to use

  • eCharts tooltip formatters — the primary use case. The formatter callback must return a string, but the tooltip content should use our design system components.
  • eCharts label formatters — similar situation where a string is required.
  • Any third-party API that accepts HTML strings — rare, but the same pattern applies.

When not to use

  • React-rendered tooltips — if the tooltip is rendered by React (e.g., a standard tooltip), just pass JSX directly.
  • Plain text — if you only need text without markup, just return a string. No need for renderToString.

Pattern: eCharts tooltip formatter

This is the most common pattern. Create a custom hook that returns a formatter function.

tsx
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:

tsx
function MyChart() {
  const formatTooltip = useMyChartTooltipFormatter();

  const option = {
    tooltip: {
      formatter: formatTooltip,
    },
    // ...
  };

  return <ReactEchartsCore option={option} />;
}

Tips

  • Wrap the formatter in 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.
  • Use design system components inside renderToString. The theme provider is wired up, so Text, Flex, Container, and other scraps primitives work as expected.
  • Keep the rendered tree small. Each call creates and tears down a React root. This is fine for tooltips (called on hover) but would be expensive in a tight loop.