Responsive Data Visualization: Charts, Graphs, and Tables for Any Screen | SoniNow Blog

Limited TimeLearn More

data visualizationchartsresponsiveuxfrontend

Responsive Data Visualization: Charts, Graphs, and Tables for Any Screen

Published

2026-06-23

Read Time

5 mins

Responsive Data Visualization: Charts, Graphs, and Tables for Any Screen

Data visualization makes abstract numbers tangible, but only if it renders well on the viewer's device. A chart that looks stunning on a 27-inch monitor but breaks on mobile isn't just a design issue—it's a communication failure. Responsive data visualization ensures insights reach every user, regardless of screen size.

SVG: The Responsive Foundation

SVG scales infinitely because it's vector-based—it never pixelates. Use an SVG-based charting library (D3.js, visx, or Charts.css) rather than canvas-based rendering for responsive contexts:

import { LineChart } from '@visx/xychart';

function SalesChart({ data }) {
  return (
    <div style={{ width: '100%', height: 400 }}>
      <LineChart
        width="100%"
        height="100%"
        data={data}
        xScale={{ type: 'time' }}
        yScale={{ type: 'linear', domain: [0, maxRevenue] }}
      >
        <Axis orientation="bottom" />
        <Axis orientation="left" />
        <LineSeries dataKey="revenue" data={data} />
      </LineChart>
    </div>
  );
}

Set chart containers to percentage-based widths and fixed or dynamic heights. Use ResizeObserver to re-render the chart when the container resizes:

import { useEffect, useRef, useState } from 'react';

function ResponsiveChart() {
  const containerRef = useRef(null);
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });

  useEffect(() => {
    const observer = new ResizeObserver((entries) => {
      const { width, height } = entries[0].contentRect;
      setDimensions({ width, height });
    });

    if (containerRef.current) {
      observer.observe(containerRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return (
    <div ref={containerRef} style={{ width: '100%', height: 400 }}>
      {dimensions.width > 0 && (
        <ActualChart width={dimensions.width} height={dimensions.height} />
      )}
    </div>
  );
}

Chart Selection for Small Screens

Not every chart type works on mobile. Apply breakpoint-aware chart transformations:

  • Bar charts: Mobile → horizontal bars. Labels fit better and users can scroll vertically.
  • Line charts: Reduce the number of series shown. A legend for 8 product lines overwhelms a 375 px screen.
  • Pie charts: Avoid below 400 px viewport width. Switch to a sorted horizontal bar chart or a data table.
  • Scatter plots: Reduce dot size and thin out data points. Aggressive overplotting makes patterns invisible.
function ChartSelector({ data, viewport }) {
  if (viewport === 'mobile') {
    return <HorizontalBarChart data={data} maxBars={8} />;
  }
  if (viewport === 'tablet') {
    return <VerticalBarChart data={data} />;
  }
  return <GroupedBarChart data={data} />;
}

Data Tables: The Underrated Visualization

A well-designed data table often communicates more effectively than a chart on mobile. Prioritize data tables for dense information:

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: clamp(0.75rem, 2vw, 0.875rem);
}

@media (max-width: 600px) {
  .data-table {
    /* Stack rows into cards on mobile */
    display: block;

    thead {
      display: none;
    }

    tr {
      display: block;
      padding: 0.75rem;
      border: 1px solid var(--color-border);
      margin-block-end: 0.5rem;
    }

    td {
      display: grid;
      grid-template-columns: 40% 60%;
      gap: 0.25rem;
      padding: 0.25rem 0;
      border: none;
    }

    td::before {
      content: attr(data-label);
      font-weight: 600;
    }
  }
}

This transforms a standard table into stacked card-like rows where each cell has a visible label. The data-label attribute on each <td> makes the context clear:

<td data-label="Revenue">$42,500</td>
<td data-label="Growth">+12.3%</td>

Interactive Elements and Touch Targets

Touch targets on charts need to be at least 44×44 px for accessibility. Adjust hit areas accordingly:

const TOUCH_TARGET = 44;

function Bar({ x, y, width, height, value, onClick }) {
  const hitWidth = Math.max(width, TOUCH_TARGET);
  const hitX = x - (hitWidth - width) / 2;

  return (
    <rect
      x={hitX}
      y={y}
      width={hitWidth}
      height={height}
      fill="transparent"
      onClick={onClick}
      style={{ cursor: 'pointer' }}
    />
  );
}

Tooltips on mobile need special handling. A hover tooltip doesn't exist on touch devices. Use tap-to-show tooltips that persist until the user taps elsewhere:

function TooltipWrapper({ children, content }) {
  const [visible, setVisible] = useState(false);

  return (
    <div
      onClick={() => setVisible(!visible)}
      onMouseEnter={() => setVisible(true)}
      onMouseLeave={() => setVisible(false)}
    >
      {children}
      {visible && <div className="tooltip">{content}</div>}
    </div>
  );
}

Loading and Empty States

Data visualizations are only useful when they have data. Handle loading, empty, and error states explicitly:

function DataVisualizer({ status, data }) {
  if (status === 'loading') {
    return <ChartSkeleton rows={5} />;
  }

  if (status === 'error') {
    return <ErrorState message="Could not load chart data" onRetry={refetch} />;
  }

  if (!data || data.length === 0) {
    return <EmptyState message="No data for the selected period" />;
  }

  return <ResponsiveChart data={data} />;
}

Skeleton states should mimic the chart layout. A bar chart skeleton uses placeholder bars; a line chart skeleton uses a wavy gradient line.

Accessibility for Data Visualizations

Charts must be accessible to screen reader users. Provide text alternatives:

<figure role="figure" aria-label="Monthly revenue January to June 2026">
  <ResponsiveChart data={revenueData} />
  <figcaption className="sr-only">
    Monthly revenue: Jan $38K, Feb $42K, Mar $45K, Apr $51K, May $55K, Jun $62K
  </figcaption>
</figure>

For complex charts, add keyboard navigation to navigate data points:

const ChartContainer = styled.div`
  &:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 2px;
  }
`;

Responsive data visualization is about adaptation, not reduction. The mobile version of a chart should communicate the same insight as the desktop version—just presented differently. SVG foundations, viewport-aware chart selection, touch-optimized interactivity, and accessible fallbacks ensure that every user sees the story in the data.

Our web development team builds responsive dashboards and data visualizations that work on any device, with full accessibility support.