Area Chart — SVG Trend Chart HTML CSS JS Snippet

Area Chart · Charts · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Catmull-Rom smooth curve
smooth derives Bézier control points from each point's neighbours, producing a natural curve that passes through every value.
Auto-scaled axis
render maps values into the plot with 15% padding so the line never touches the edges and small changes stay visible.
SVG gradient area
The area reuses the line path closed to the baseline and fills with an in-markup linearGradient that clips to the curve.
Hover crosshair
A mousemove listener snaps a dot and a dashed vertical line to the nearest point using getBoundingClientRect mapping.
Live value readout
The header value and month update to the hovered point, with a floating tooltip showing the exact figure.
Touch support
A touchmove handler reuses the same nearest-point logic so the crosshair works on phones.
Fluid sizing
preserveAspectRatio="none" stretches the viewBox to the card width; the math is resolution-independent, so no resize code.
Decluttered labels
X-axis labels render every other month, keeping the axis readable on narrow screens.

About this UI Snippet

Area Chart — Smooth Catmull-Rom Curve, Gradient Fill & Hover Crosshair

Screenshot of the Area Chart snippet rendered live

An area chart is the go-to for showing a single metric's trend over time — active users, revenue, temperature — where the filled area under the line emphasises volume and growth. This snippet draws one with an SVG <path> in HTML, CSS, and vanilla JavaScript: a smooth curve through the data points, a gradient area fill, baseline gridlines, and an interactive hover crosshair with a dot, a value readout, and a tooltip.

Smooth curve via Catmull-Rom

Straight line segments between points look jagged; a true smooth curve reads as a polished chart. The smooth function converts the data points into a cubic Bézier path using the Catmull-Rom-to-Bézier formula: for each point it derives two control points from the slope of its neighbours ((p2 - p0) / 6), producing a curve that passes through every data point while flowing naturally between them. This is the same technique charting libraries use for their "smooth"/"natural" line mode, implemented in a dozen lines.

Auto-scaled, gradient-filled area

render computes the data's min and max, adds 15% padding so the line never touches the chart edges, and maps each value into the plot area. The line path is built once with smooth; the area path reuses that exact line and closes it down to the baseline (L X1 BOT L X0 BOT Z), then fills with an SVG linearGradient that fades from translucent to transparent. Using an in-markup SVG gradient (not a CSS background) means the fill clips perfectly to the curved area and renders identically across every framework export.

Hover crosshair and readout

A mousemove listener on the plot maps the cursor's horizontal position to the nearest data index using getBoundingClientRect (so it works regardless of the chart's CSS size versus its viewBox). It then positions a marker dot on that point, draws a dashed vertical crosshair line, updates the big value/month readout in the header, and floats a small tooltip above the point. Leaving the chart hides them and resets the readout. A touchmove handler maps the same logic for mobile.

Responsive by default

preserveAspectRatio="none" lets the 320×170 viewBox stretch to the card width, and the coordinate mapping in render is resolution-independent, so the chart is fluid with no resize handling. The x-axis labels render every other month to avoid crowding on narrow screens.

Swap the DATA array for your figures and it redraws. Pair this with a realtime line chart for live streams, a stacked bar chart for composition, or a sparkline chart for compact trends.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than deriving the Bezier control point formula by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to walk through exactly why the smooth() function divides the neighbor-point differences by 6 to get its control points, or how the min/max padding of 15% keeps the curve from touching the plot edges. The same assistant is useful for optimizing it — ask whether recomputing the entire pts array and both path strings on every render call makes sense for a chart that updates frequently, or whether the nearest-point lookup in onMove could be replaced with a binary search for a much larger DATA array. It's also a good way to extend the chart: ask it to render two overlapping series with independent gradients, add a pinch-to-zoom range selector, or animate the area path drawing in on load with a stroke-dashoffset reveal. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a smooth "area chart" in plain HTML, CSS, and JavaScript using only inline SVG — no charting library, no canvas.

Requirements:
- An SVG with preserveAspectRatio="none" so a fixed-size viewBox stretches fluidly to the container's actual rendered width, without any JS resize handling.
- Convert an array of { label, value } data points into pixel coordinates by computing the data's min and max, adding roughly 15 percent padding to both ends so the curve never touches the top or bottom of the plot area, then linearly mapping each value into that padded range.
- Connect the mapped points with a true smooth curve using the Catmull-Rom-to-Bezier technique: for each point, derive two cubic Bezier control points from the positions of its immediate neighbors (not just a generic spline library), so the resulting path passes exactly through every original data point rather than merely approximating them.
- Reuse that exact line path string to build a second, closed path that drops down to a shared baseline and back up to the first point, and fill it with an SVG linearGradient (defined in the SVG's defs, not a CSS background) that fades from a translucent color at the top to fully transparent at the bottom.
- Add a mousemove (and touchmove) listener on the chart container that uses getBoundingClientRect to convert the cursor's x position into the nearest data index, then moves a small circle marker and a dashed vertical crosshair line to that point's exact coordinates, and updates a header readout and a floating tooltip with that data point's value and label.
- On mouseleave, hide the marker, crosshair, and tooltip and reset the header readout to its idle state.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA "Monthly active users" card appears with a smooth gradient-filled area curve across twelve months and a peak readout.
  2. 2
    Hover the chartA dot snaps to the nearest month, a dashed vertical line marks it, and the header shows that month's value.
  3. 3
    Read the tooltipA small tooltip floats above the hovered point with the exact value, tracking your cursor across the months.
  4. 4
    Move along the curveAs you sweep across, the crosshair and readout update to the nearest data point in real time.
  5. 5
    On mobileDrag a finger across the chart — the same crosshair and readout follow your touch.
  6. 6
    Plug in your dataReplace the DATA array with your { m, v } points; the curve auto-scales to the min/max with padding.

Real-world uses

Common Use Cases

Growth and usage trends
Monthly active users, signups, or sessions over time. Pair with a metric card grid for headline stats.
Revenue and finance charts
MRR, sales, or balance over months with the area emphasising cumulative volume.
Analytics dashboards
A trend panel beside a stacked bar chart for composition and a funnel chart for conversion.
Monitoring and metrics
Slower-moving metrics (daily averages) where a smooth area reads better than a live ticker; for live data use a realtime line chart.
Weather and sensor history
Temperature or reading history with a gradient area and hover values for each point.
Report and email embeds
A clean, dependency-free trend chart for static reports; compact variants pair with a sparkline chart.

Got questions?

Frequently Asked Questions

Replace the DATA array with your { m, v } points (any length) and call render. It recomputes the min/max with padding and remaps every point, so the curve, area, gridlines, and peak adapt automatically. For non-monthly data, just change the label field and the x-axis renderer.

Render a second line and area from another data array with its own gradient and colour, layering the paths in the SVG. Add both values to the hover tooltip. For comparison readability, give the second series a distinct hue and a slightly lower area opacity so the overlap stays legible.

Catmull-Rom produces a smooth curve that still passes through every actual data point, so values are not visually distorted — unlike a basis spline, which only approximates the points. Straight segments are accurate but jagged. Catmull-Rom is the sweet spot most dashboards use for "smooth" lines, and it is cheap to compute.

Give the SVG role="img" with an aria-label summarising the trend, and expose the underlying data as an off-screen or toggleable data table for screen-reader users. The hover readout is mouse-only, so also ensure the key figures (latest, peak) appear as real text in the header, which they do here.

In React, compute the path strings with useMemo from your data and render them in JSX; track the hovered index in useState for the crosshair, updating it in an onMouseMove. In Vue, use a computed for the paths and a ref for hover. In Angular, compute in the component and bind [attr.d]. The Catmull-Rom function and gradient port unchanged.