webdevpuneet.com

Line Chart Widget — Free HTML CSS JS SVG Snippet

Line Chart Widget · Charts · Plain HTML, CSS & JS · Live preview

CategoryCharts

Copy & paste

Source Code

<div class="wrap">

  <div class="card">
    <div class="card-head">
      <div>
        <div class="card-title">Revenue</div>
        <div class="card-val">$48,295 <span class="card-change up">↑ 12.4%</span></div>
      </div>
      <div class="period-tabs">
        <button class="ptab active" onclick="setPeriod(this,0)">7d</button>
        <button class="ptab" onclick="setPeriod(this,1)">30d</button>
        <button class="ptab" onclick="setPeriod(this,2)">90d</button>
      </div>
    </div>

    <div class="chart-area">
      <svg class="chart" id="chart" viewBox="0 0 420 120" preserveAspectRatio="none">
        <defs>
          <linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stop-color="#6366f1" stop-opacity="0.18"/>
            <stop offset="100%" stop-color="#6366f1" stop-opacity="0"/>
          </linearGradient>
        </defs>
        <path class="area" id="area" d="" fill="url(#areaGrad)"/>
        <path class="line" id="line" d="" fill="none" stroke="#6366f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <circle class="dot" id="dot" r="4" fill="#6366f1" stroke="#fff" stroke-width="2"/>
        <!-- Y gridlines -->
        <line x1="0" y1="30" x2="420" y2="30" stroke="#e2e8f0" stroke-width="0.5"/>
        <line x1="0" y1="60" x2="420" y2="60" stroke="#e2e8f0" stroke-width="0.5"/>
        <line x1="0" y1="90" x2="420" y2="90" stroke="#e2e8f0" stroke-width="0.5"/>
      </svg>

      <div class="tooltip" id="tooltip" style="display:none">
        <div class="tt-date" id="tt-date"></div>
        <div class="tt-val" id="tt-val"></div>
      </div>
    </div>

    <div class="x-labels" id="x-labels"></div>

    <div class="chart-footer">
      <div class="legend-item"><span class="legend-dot indigo"></span>Revenue</div>
      <div class="stat-pair"><span class="sl">Peak</span><strong id="peak">—</strong></div>
      <div class="stat-pair"><span class="sl">Avg</span><strong id="avg">—</strong></div>
    </div>
  </div>

</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

SVG line chart: M/L path built from normalised (x,y) coordinate pairs
Gradient area fill: linearGradient in SVG defs, transparent fade-out bottom
Mousemove tooltip: getBoundingClientRect coordinate conversion, closest-point finder
Tracking dot: SVG circle moves to nearest data point on hover
Period tabs: 3 datasets, renderChart() regenerates all SVG paths on tab click
Y gridlines: 3 horizontal SVG lines at 25%/50%/75% height
Peak and average footer: computed from data array on each render
No chart library — pure SVG, CSS, and vanilla JavaScript

About this UI Snippet

Line Chart Widget — SVG Line & Area Chart with Mousemove Tooltip and Period Tab Switcher

Screenshot of the Line Chart Widget snippet rendered live

If you need a revenue or metric line chart for a dashboard without importing a charting library, this snippet builds a complete SVG line chart from scratch: a normalised SVG polyline path, a gradient area fill, a mousemove tooltip with a tracking dot, a period tab switcher (7d / 30d / 90d), and a footer with peak and average statistics — all in plain HTML, CSS, and vanilla JavaScript.

How the SVG path is generated

The chart function takes the data array and normalises each value to an SVG coordinate. The X position is evenly distributed: x = pad + (i / (n-1)) * (svgW - pad*2). The Y position inverts the scale: y = svgH - pad - ((val - min) / (max - min)) * (svgH - pad*2) — subtracting from svgH because SVG Y increases downward. These (x,y) points form an array of coordinate pairs. The SVG path D attribute is built by joining M (moveto) for the first point and L (lineto) for each subsequent point.

The gradient area fill

A linearGradient element in the SVG defs fades from indigo at 18% opacity to transparent. The area path starts at the line path, then closes back along the bottom edge of the chart (L to the last x at svgH, then L to the first x at svgH, then Z). The fill is set to url(#areaGrad).

The mousemove tooltip

On mousemove over the SVG, the mouse X position is converted from pixel coordinates to SVG coordinates using getBoundingClientRect(). The closest data point is found by comparing each point X to the converted mouse X. The tracking dot is moved to that point, and the tooltip div is positioned using percentage-based left/top derived from the SVG coordinate divided by svgW and svgH.

Period tab switcher

Three datasets (7 days, 30 days, 90 days) are stored as separate arrays. Clicking a period tab calls renderChart(idx) which regenerates all SVG paths, updates the header total and change, and refills the X axis labels and footer stats.

No library required

This pattern replaces Chart.js or Recharts for simple single-series line charts. The full implementation is under 100 lines of JavaScript.

Step by step

How to Use

  1. 1
    Hover over the chartMove the cursor across the chart area to see the tracking dot and tooltip update. The tooltip shows the date label and value for the nearest data point.
  2. 2
    Click the period tabsSwitch between 7d, 30d, and 90d. Each tab loads a different dataset, regenerates the SVG path, and updates the header total, change percentage, and footer stats.
  3. 3
    Replace the data arraysIn the JS panel, update the vals arrays in each dataset object. The chart automatically normalises any range of values to fit the 120px SVG height.
  4. 4
    Change the chart colourReplace #6366f1 in the CSS and SVG attributes with your brand hex. Update both the stroke colour on the line path and the stop-color in the linearGradient.
  5. 5
    Change the metric labelUpdate "Revenue" in the .card-title and the total/change strings in each dataset object. Add more stat-pair entries in the footer for additional metrics like Min or Total.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component using useState for period and useMemo for chart path calculation, or "Tailwind" for a Tailwind CSS version.

Real-world uses

Common Use Cases

SaaS revenue and MRR dashboard widgets
Show monthly recurring revenue, daily active users, or conversion rate trends in a card widget. The period tab switcher (7d/30d/90d) is the standard pattern for metric time series on SaaS dashboards — exactly the same interaction users expect from Stripe, Mixpanel, and Amplitude. For a compact inline variant, drop in a sparkline chart instead.
Analytics overview and traffic chart widgets
Adapt for page views, sessions, or API call counts. Update the card title and datasets. The normalised SVG approach handles any numeric range without configuration — whether values are in the hundreds or millions.
E-commerce sales and order volume tracking
Show daily order counts or GMV over 7, 30, or 90 days, or switch to a realtime line chart for live streaming data. Add a second SVG line in a different colour (e.g. green) to compare two metrics on the same chart — duplicate the line and area paths with different data arrays.
Learn SVG path generation and coordinate normalisation
The chart builds its path entirely from coordinate math — no third-party library needed. Studying this snippet teaches how SVG viewBox coordinates work, how to normalise arbitrary data ranges to pixel heights, and how to map mouse position to data point index.
Executive and management dashboard summary cards
The card layout with large metric value, change percentage, chart, and footer stats is the standard executive dashboard summary pattern. Pair with the Stats Card snippet for KPI rows above a more detailed line chart.
Replace Chart.js for simple single-series line charts
Chart.js adds ~60KB of JavaScript for a use case this snippet handles in under 100 lines. For dashboards with 2-3 simple metric charts, this zero-dependency SVG approach avoids the bundle size overhead with identical visual output — mix it with a donut chart for part-to-whole breakdowns.
Related: Real-Time Streaming Metric Chart with Pause/Resume
See the Real-Time Streaming Metric Chart with Pause/Resume for a related charts pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Each data value is converted to an (x,y) SVG coordinate. X is evenly distributed: x = pad + (index / (n-1)) * (svgWidth - pad*2). Y is normalised and inverted: y = svgHeight - pad - ((value - min) / (max - min)) * (svgHeight - pad*2). Subtracting from svgHeight inverts the scale because SVG Y increases downward. These points are joined into an SVG path D string: "M x0,y0 L x1,y1 L x2,y2 ...".

The mousemove handler reads e.clientX and the chart SVG's getBoundingClientRect() to compute xRel — the cursor position in SVG coordinate units. It then iterates all point X coordinates and tracks the index with the minimum absolute distance to xRel. That index selects the tooltip label, value, and dot position. The dot and tooltip update on every mousemove event.

Add a second path element to the SVG with a different stroke colour: <path id="line2" fill="none" stroke="#10b981" stroke-width="2"/>. In renderChart(), compute pts2 from the second data array using the same coordinate math. Set document.getElementById("line2").setAttribute("d", lineD2). Add a second legend dot in the footer with the new colour.

Click "JSX" to download. Manage activePeriod with useState. Compute pts with useMemo from the active dataset — recalculate only when activePeriod or data changes. Set the SVG path d attribute via a state variable that updates when pts change. For the tooltip, use useState for hover position and onMouseMove on the SVG element.