# Stat card / Tarjeta de métrica

> Figure, change and a small trend line.

Page: https://componentes-lovat.vercel.app/c/stat-card/  
License: MIT · Design: coss ui (MIT) · card.tsx, sidebar.tsx (aspecto)  
Requires: tokens.css  
Context: herramienta · Density: media · Tone: sobria

## Files

- Tokens (once): https://componentes-lovat.vercel.app/tokens.css
- HTML: https://componentes-lovat.vercel.app/raw/stat-card/stat-card.html
- CSS: https://componentes-lovat.vercel.app/raw/stat-card/stat-card.css
- JS: https://componentes-lovat.vercel.app/raw/stat-card/stat-card.js
- Everything in one file: https://componentes-lovat.vercel.app/r/stat-card.html

Dark theme: add class `dark` to `<html>`.

## When to use

- For 3 or 4 key numbers at the top of a dashboard.

## When not to use

- More than 4 in a row: it loses focus.
- With figures you can't source.

## Accessibility

Roles: article, heading

- Figure and change are text; the sparkline is decorative (aria-hidden).
- Change uses an arrow and text, not green or red.

## Code

```html
<div class="c-stat-grid">
  <article class="c-stat">
    <h3 class="c-stat__label">Ingresos</h3>
    <p class="c-stat__value">S/ 48 200</p>
    <p class="c-stat__delta"><span aria-hidden="true">↑</span> 12 % <span class="c-stat__vs">frente a agosto</span></p>
    <svg class="c-stat__spark" data-values="31,33,30,36,38,37,41,44,43,48" aria-hidden="true" focusable="false"></svg>
  </article>
  <article class="c-stat">
    <h3 class="c-stat__label">Pedidos</h3>
    <p class="c-stat__value">1 130</p>
    <p class="c-stat__delta"><span aria-hidden="true">↑</span> 7 % <span class="c-stat__vs">frente a agosto</span></p>
    <svg class="c-stat__spark" data-values="88,92,95,90,99,104,101,108,110,113" aria-hidden="true" focusable="false"></svg>
  </article>
  <article class="c-stat">
    <h3 class="c-stat__label">Devoluciones</h3>
    <p class="c-stat__value">2,1 %</p>
    <p class="c-stat__delta"><span aria-hidden="true">↓</span> 0,4 pts <span class="c-stat__vs">frente a agosto</span></p>
    <svg class="c-stat__spark" data-values="2.9,2.7,2.8,2.6,2.5,2.6,2.3,2.4,2.2,2.1" aria-hidden="true" focusable="false"></svg>
  </article>
</div>
<p class="c-stat-note">Cifras de ejemplo.</p>
```

```css
/* Tarjeta de métrica con mini-gráfico (sparkline). Aspecto de la tarjeta de coss ui; color solo del tema.
   La variación lleva flecha y texto: no depende de verde o rojo. Necesita tokens.css. */
.c-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 1rem; width: 100%; max-width: 44rem; }
.c-stat { position: relative; display: grid; gap: .25rem; padding: 1.125rem 1.25rem 1rem; border: 1px solid var(--border); border-radius: calc(var(--radius) + 6px); background: var(--card); color: var(--card-foreground); box-shadow: 0 1px 2px 0 #0000000d; }
.c-stat__label { margin: 0; font-size: .8125rem; font-weight: 500; color: var(--muted-foreground); }
.c-stat__value { margin: 0; font-size: 1.75rem; line-height: 1.15; font-weight: 600; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.c-stat__delta { margin: 0; font-size: .8125rem; font-weight: 500; font-variant-numeric: tabular-nums; }
.c-stat__vs { font-weight: 400; color: var(--muted-foreground); }
.c-stat__spark { display: block; width: 100%; height: 36px; margin-top: .5rem; overflow: visible; color: var(--primary); }
.c-stat__spark polyline { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.c-stat__spark line { stroke: var(--border); stroke-width: 1; vector-effect: non-scaling-stroke; }
.c-stat-note { margin: .5rem 0 0; font-size: .75rem; color: var(--muted-foreground); }
```

```js
/* Sparkline: lee data-values="1,2,3" y dibuja la línea a lo ancho de la tarjeta. Decorativa (aria-hidden):
   la cifra y la variación ya están en texto. */
(function () {
  const C = (window.Componentes = window.Componentes || {});
  const SVG = 'http://www.w3.org/2000/svg';
  function draw(svg) {
    const v = (svg.dataset.values || '').split(',').map(Number).filter((x) => !isNaN(x));
    if (v.length < 2) return;
    const min = Math.min(...v), max = Math.max(...v), span = max - min || 1;
    svg.setAttribute('viewBox', '0 0 100 36');
    svg.setAttribute('preserveAspectRatio', 'none');
    svg.innerHTML = '';
    const base = document.createElementNS(SVG, 'line');
    Object.entries({ x1: 0, x2: 100, y1: 35.5, y2: 35.5 }).forEach(([k, x]) => base.setAttribute(k, x));
    svg.appendChild(base);
    const p = document.createElementNS(SVG, 'polyline');
    p.setAttribute('points', v.map((x, i) => `${(i / (v.length - 1)) * 100},${32 - ((x - min) / span) * 28}`).join(' '));
    svg.appendChild(p);
  }
  function init(root) {
    (root || document).querySelectorAll('.c-stat__spark[data-values]:not([data-c-ready])').forEach((s) => {
      s.dataset.cReady = '';
      try { draw(s); } catch (e) { console.warn('[stat-card]', e); }
    });
  }
  C.statCard = { init, draw };
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => init());
  else init();
})();
```

## Credits

- coss ui (MIT) · card.tsx, sidebar.tsx (aspecto): https://coss.com/ui
