Ir al contenido

Candle chart

Gráfico estático de velas OHLC renderizado solo con CSS.

Navegadores
Chrome 123+Firefox 121+Safari 17.5+
Nivel
0
Presupuesto de diseño forzado
0 ms
Presupuesto de axe
0
Compatible con SSR
Sí
Contrato publicado
Entorno de pruebas

Zona de pruebas

Candle chart

100 daily OHLC items with CSS geometry, automatic axes, and an optional interactive client entry.

CSS-only chart

BTC / USD daily candles
TimeOpenHighLowClose
2025-08-2024000242002387524060
2025-08-2124166245672402324405
2025-08-2224324245082410224263
2025-08-2324470246762423624415
2025-08-2424598250522447324824
2025-08-2524703248612456024721
2025-08-2624782249442446824629
2025-08-2724834251552465524971
2025-08-2824859251562473424950
2025-08-2924859250872451524658
2025-08-3024836249802467524840
2025-08-3124797250922461824930
2025-09-0124746249302443924564
2025-09-0224689248952441524558
2025-09-0324633249932447224765
2025-09-0424584247242430324482
2025-09-0524548247102420224327
2025-09-0624530248032438724619
2025-09-0724533247522437224546
2025-09-0824559247872414324322
2025-09-0924609247662448424626
2025-09-1024683249692454024807
2025-09-1124776249602444124602
2025-09-1224886250922464724826
2025-09-1325008254312488325203
2025-09-1425135252752493925082
2025-09-1525261254232498325144
2025-09-1625380257652520125581
2025-09-1725486257782536125572
2025-09-1825574258022529625439
2025-09-1925639259192547825779
2025-09-2025678260352549925873
2025-09-2125691258752545525580
2025-09-2225678259162553525710
2025-09-2325641261072548025879
2025-09-2425582257222535325532
2025-09-2525507256692529425419
2025-09-2625422258082527925624
2025-09-2725332255642517125358
2025-09-2825246254742488725066
2025-09-2925168254072504325267
2025-09-3025106253612496325199
2025-10-0125064252482469124852
2025-10-0225046252522483025009
2025-10-0325055254132493025185
2025-10-0425092252322477524918
2025-10-0525156253182483524996
2025-10-0625245255542506625370
2025-10-0725354255602515225277
2025-10-0825480257082510825251
2025-10-0925616258352545525695
2025-10-1025755259632557625801
2025-10-1125892260762554625671
2025-10-1226021262362587826030
2025-10-1326135265182597426290
2025-10-1426230263702591126090
2025-10-1526302264642611326238
2025-10-1626351267482620826564
2025-10-1726376265822620326364
2025-10-1826379266072608426263
2025-10-1926361267012623626561
2025-10-2026329266102618626448
2025-10-2126286264702599426155
2025-10-2226239265652606026359
2025-10-2326194266322606926404
2025-10-2426158262982591226055
2025-10-2526136262982597426135
2025-10-2626134265482595526364
2025-10-2726154263602598726112
2025-10-2826199264272593326076
2025-10-2926271265842611026444
2025-10-3026368265622618926400
2025-10-3126488266722615926284
2025-11-0126627268922648426686
2025-11-0226780271042661926876
2025-11-0326941270812654526724
2025-11-0427103272652690427029
2025-11-0527261275732711827389
2025-11-0627406276122708727248
2025-11-0727535277632717427353
2025-11-0827641279012751627761
2025-11-0927721278832753227675
2025-11-1027774279582738527546
2025-11-1127799280782762027872
2025-11-1227797281082767227880
2025-11-1327771279112743027573
2025-11-1427726278902756527728
2025-11-1527666280352748727851
2025-11-1627598278042737027495
2025-11-1727527277552731527458
2025-11-1827462278272730127687
2025-11-1927407275952722827433
2025-11-2027368275522712527250
2025-11-2127349277462720627540
2025-11-2227353277272719227499
2025-11-2327382275222707427253
2025-11-2427435276892731027527
2025-11-2527510279102736727726
2025-11-2627604278102734527506
2025-11-2727712279402749527674

Interactive chart

Interactive BTC / USD daily candles
2025-11-27O 27712H 27940L 27495C 27674
  1. Aug 25
  2. Sep 25
  3. Oct 25
  4. Nov 25
  1. 28,108
  2. 27,261.4
  3. 26,414.8
  4. 25,568.2
  5. 24,721.6
  6. 23,875
TimeOpenHighLowClose
2025-08-2024000242002387524060
2025-08-2124166245672402324405
2025-08-2224324245082410224263
2025-08-2324470246762423624415
2025-08-2424598250522447324824
2025-08-2524703248612456024721
2025-08-2624782249442446824629
2025-08-2724834251552465524971
2025-08-2824859251562473424950
2025-08-2924859250872451524658
2025-08-3024836249802467524840
2025-08-3124797250922461824930
2025-09-0124746249302443924564
2025-09-0224689248952441524558
2025-09-0324633249932447224765
2025-09-0424584247242430324482
2025-09-0524548247102420224327
2025-09-0624530248032438724619
2025-09-0724533247522437224546
2025-09-0824559247872414324322
2025-09-0924609247662448424626
2025-09-1024683249692454024807
2025-09-1124776249602444124602
2025-09-1224886250922464724826
2025-09-1325008254312488325203
2025-09-1425135252752493925082
2025-09-1525261254232498325144
2025-09-1625380257652520125581
2025-09-1725486257782536125572
2025-09-1825574258022529625439
2025-09-1925639259192547825779
2025-09-2025678260352549925873
2025-09-2125691258752545525580
2025-09-2225678259162553525710
2025-09-2325641261072548025879
2025-09-2425582257222535325532
2025-09-2525507256692529425419
2025-09-2625422258082527925624
2025-09-2725332255642517125358
2025-09-2825246254742488725066
2025-09-2925168254072504325267
2025-09-3025106253612496325199
2025-10-0125064252482469124852
2025-10-0225046252522483025009
2025-10-0325055254132493025185
2025-10-0425092252322477524918
2025-10-0525156253182483524996
2025-10-0625245255542506625370
2025-10-0725354255602515225277
2025-10-0825480257082510825251
2025-10-0925616258352545525695
2025-10-1025755259632557625801
2025-10-1125892260762554625671
2025-10-1226021262362587826030
2025-10-1326135265182597426290
2025-10-1426230263702591126090
2025-10-1526302264642611326238
2025-10-1626351267482620826564
2025-10-1726376265822620326364
2025-10-1826379266072608426263
2025-10-1926361267012623626561
2025-10-2026329266102618626448
2025-10-2126286264702599426155
2025-10-2226239265652606026359
2025-10-2326194266322606926404
2025-10-2426158262982591226055
2025-10-2526136262982597426135
2025-10-2626134265482595526364
2025-10-2726154263602598726112
2025-10-2826199264272593326076
2025-10-2926271265842611026444
2025-10-3026368265622618926400
2025-10-3126488266722615926284
2025-11-0126627268922648426686
2025-11-0226780271042661926876
2025-11-0326941270812654526724
2025-11-0427103272652690427029
2025-11-0527261275732711827389
2025-11-0627406276122708727248
2025-11-0727535277632717427353
2025-11-0827641279012751627761
2025-11-0927721278832753227675
2025-11-1027774279582738527546
2025-11-1127799280782762027872
2025-11-1227797281082767227880
2025-11-1327771279112743027573
2025-11-1427726278902756527728
2025-11-1527666280352748727851
2025-11-1627598278042737027495
2025-11-1727527277552731527458
2025-11-1827462278272730127687
2025-11-1927407275952722827433
2025-11-2027368275522712527250
2025-11-2127349277462720627540
2025-11-2227353277272719227499
2025-11-2327382275222707427253
2025-11-2427435276892731027527
2025-11-2527510279102736727726
2025-11-2627604278102734527506
2025-11-2727712279402749527674

Live stream

A simulated trade feed with volatility clustering and drifting trends. Every candle lives in a horizontal VirtualScroll sized to show 20 at a time: scroll back through the history, and the chart follows new candles again once you return to the newest one.

Live BTC / USD one-minute candles
10:29O 63973.85H 63993.3L 63888.51C 63888.51
  1. 10:05
  2. 10:10
  3. 10:15
  4. 10:20
  5. 10:25
  1. 64,365.59
  2. 64,251.48
  3. 64,137.38
  4. 64,023.27
  5. 63,909.17
  6. 63,795.06
TimeOpenHighLowClose
10:1064342.7464343.9664284.564343.96
10:1164343.9664365.5964281.2964365.59
10:1264365.5964365.5964268.4564323.33
10:1364323.3364354.5464279.5964316.85
10:1464316.8564316.8564192.764226.09
10:1564226.0964226.0964147.2264162.9
10:1664162.964211.2764118.7664118.76
10:1764118.7664150.4664028.6764061.06
10:1864061.0664061.0663901.4263901.42
10:1963901.4263901.4263811.1663867.61
10:2063867.6163899.4163795.0663795.06
10:2163795.0663864.0763795.0663859.14
10:2263859.1463895.1863832.4963895.18
10:2363895.1863895.1863820.0263833.26
10:2463833.2663910.9563827.5463910.95
10:2563910.9563980.3763896.7463975.28
10:2663975.2864031.1463961.3564017.19
10:2764017.1964106.4764017.1964102.34
10:2864102.3464118.4863973.1863973.85
10:2963973.8563993.363888.5163888.51
import { useEffect, useState } from "react";
import { CandleChart } from "@gunkin/uiify";
import { CandleChartClient } from "@gunkin/uiify/components/candle-chart/client";

const data = Array.from({ length: 100 }, (_, index) => {
  const open = Math.round(24000 + index * 38 + Math.sin(index / 4) * 420);
  const close = open + Math.round(Math.sin(index * 1.9) * 190);

  return {
    time: new Date(Date.UTC(2025, 7, 20 + index)).toISOString().slice(0, 10),
    open,
    high: Math.max(open, close) + 180,
    low: Math.min(open, close) - 160,
    close,
  };
});

export default function Example() {
  return (
    <>
      <CandleChart className="" data={data} aria-label="BTC / USD daily candles" />
      <CandleChartClient className="" data={data} aria-label="Interactive BTC / USD daily candles" />
      <LiveChart />
    </>
  );
}

function LiveChart() {
  const [candles, setCandles] = useState(data);
  const [running, setRunning] = useState(false);

  useEffect(() => {
    if (!running) return;
    const timer = setInterval(() => {
      setCandles((current) => {
        const last = current.at(-1);
        if (!last) return current;
        const close = Math.round(last.close * (1 + (Math.random() - 0.5) * 0.004));
        const next = {
          time: String(current.length),
          open: last.close,
          high: Math.max(last.close, close),
          low: Math.min(last.close, close),
          close,
        };
        return [...current, next];
      });
    }, 1000);
    return () => clearInterval(timer);
  }, [running]);

  return (
    <>
      <button type="button" onClick={() => setRunning((value) => !value)}>
        {running ? "Stop" : "Start"}
      </button>
      {/* All candles, virtualized; 20 fit the viewport and new ones stay in view at the end. */}
      <CandleChartClient className="" data={candles} visibleCount={20} aria-label="Live BTC / USD candles" />
    </>
  );
}
@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  [data-uiify-candle-chart] {
    --candle-grid: color-mix(in srgb, currentcolor 10%, transparent);
    --candle-down: oklch(64% 0.21 24deg);
    --candle-flat: color-mix(in srgb, currentcolor 60%, transparent);
    --candle-up: oklch(67% 0.14 166deg);
    --candle-axis: var(--muted-foreground);

    position: relative;
    display: block;
    inline-size: 100%;
    min-block-size: 21rem;
    padding: 1rem 0.75rem 0.5rem;
    overflow: clip;
    overscroll-behavior: none;
    isolation: isolate;
    color-scheme: light dark;
    background: transparent;
    color: light-dark(oklch(28% 0.04 165deg), oklch(82% 0.04 165deg));
  }

  /* Interactive charts own touch and horizontal wheel gestures (crosshair,
     zoom, native scroll); a static chart leaves page scrolling alone. */
  [data-uiify-candle-chart][data-interactive] {
    touch-action: none;
  }

  [data-uiify-candle-chart][data-interactive] [data-part="scroll-viewport"] {
    overscroll-behavior-inline: none;
  }

  /* The time-axis row also reserves the horizontal scrollbar, measured by the
     client entry (0 for overlay scrollbars and static charts), so the flexible
     candle row does not absorb it and stays aligned with the value axis. */
  [data-uiify-candle-chart] > [data-part="plot"] {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 4.5rem;
    grid-template-rows: minmax(18rem, 1fr) calc(1.5rem + var(--candle-scrollbar-size, 0px));
    gap: 0 0.75rem;
    min-inline-size: 0;
    min-block-size: 18rem;
    overscroll-behavior: none;
  }

  [data-uiify-candle-chart] [data-part="scroll-viewport"] {
    grid-column: 1;
    grid-row: 1 / span 2;
    min-inline-size: 0;
    min-block-size: 18rem;
    overflow: auto hidden;
    container-type: inline-size;
    direction: rtl;
  }

  [data-uiify-candle-chart] [data-part="canvas"] {
    display: grid;
    grid-template-rows: minmax(18rem, 1fr) 1.5rem;
    inline-size: calc(100% * var(--candle-scale));
    min-inline-size: 100%;
    min-block-size: 100%;
    direction: ltr;
  }

  [data-uiify-candle-chart] [data-part="candles"] {
    position: absolute;
    inset-block: 0;
    inset-inline: auto 0;
    inline-size: 100%;
    margin: 0;
    padding: 1rem 0.5rem;
    list-style: none;
  }

  /* Live mode: a horizontal VirtualScroll replaces the static list. The grid sits
     on the viewport, so it holds still while candles scroll past and a classic
     scrollbar cannot squeeze it. */
  [data-uiify-candle-chart] [data-part="viewport"] > [data-uiify-virtual-scroll] {
    position: absolute;
    inset: 0;
  }

  /* A classic scrollbar shortens the virtual rows; size candles from the plot
     height so they stay aligned with the price axis. */
  [data-uiify-candle-chart] [data-uiify-virtual-scroll] [data-part="candle"] {
    inset-block: 1rem auto;
    block-size: calc(var(--candle-plot-height, 18rem) - 2rem);
  }

  [data-uiify-candle-chart] [data-part="candles"],
  [data-uiify-candle-chart] [data-part="viewport"]:has(> [data-uiify-virtual-scroll]) {
    background-image:
      linear-gradient(to right, var(--candle-grid) 1px, transparent 1px),
      linear-gradient(to bottom, var(--candle-grid) 1px, transparent 1px);
    background-size:
      10% 100%,
      100% 25%;
  }

  [data-uiify-candle-chart] [data-part="viewport"] {
    position: relative;
    grid-column: 1;
    grid-row: 1;
    min-inline-size: 0;
    min-block-size: 18rem;
    overflow: clip;
    overscroll-behavior: none;
  }

  [data-uiify-candle-chart] [data-part="time-viewport"] {
    position: relative;
    grid-column: 1;
    grid-row: 2;
    min-inline-size: 0;
    overflow: clip;
    overscroll-behavior: none;
  }

  [data-uiify-candle-chart] > figcaption {
    position: absolute;
    z-index: 1;
    inset-block-start: 0.75rem;
    inset-inline-start: 1rem;
    color: var(--muted-foreground);
    font-size: 0.75rem;
    font-weight: 650;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  [data-uiify-candle-chart] [data-part="readout"] {
    position: absolute;
    z-index: 1;
    inset-block-start: 0.75rem;
    inset-inline-end: 1rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem 0.625rem;
    align-items: baseline;
    color: var(--candle-axis);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    white-space: nowrap;
  }

  [data-uiify-candle-chart] [data-part="readout-time"] {
    font-weight: 650;
  }

  [data-uiify-candle-chart] [data-part="candle"] {
    position: absolute;
    inset: 1rem 0.5rem;
    pointer-events: none;
    inset-inline-start: var(--candle-x);
    inline-size: var(--candle-slot);
    display: block;
    color: var(--candle-flat);
    list-style: none;
  }

  [data-uiify-candle-chart][data-interactive] [data-part="candle"] {
    pointer-events: auto;
  }

  [data-uiify-candle-chart] [data-part="candle-hit"] {
    position: absolute;
    z-index: 1;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    appearance: none;
    background: transparent;
    color: transparent;
    cursor: crosshair;
    font: inherit;
  }

  [data-uiify-candle-chart] [data-part="candle"]::before,
  [data-uiify-candle-chart] [data-part="candle"]::after {
    content: "";
    position: absolute;
    display: block;
    background: currentcolor;
  }

  [data-uiify-candle-chart] [data-part="candle"]::before {
    inset-block-start: var(--candle-wick-top);
    inset-inline-start: 50%;
    inline-size: max(1px, 0.08em);
    block-size: var(--candle-wick-height);
    transform: translateX(-50%);
  }

  [data-uiify-candle-chart] [data-part="candle"]::after {
    inset-block-start: var(--candle-body-top);
    inset-inline: 17%;
    block-size: var(--candle-body-height);
    min-block-size: 1px;
  }

  [data-uiify-candle-chart] [data-part="candle"][data-direction="up"] {
    color: var(--candle-up);
  }

  [data-uiify-candle-chart] [data-part="candle"][data-direction="down"] {
    color: var(--candle-down);
  }

  /* The crosshair and time axis span the scrolled content in live mode:
     `--candle-content-size` is its width, `--candle-scroll-x` its scroll offset. */
  [data-uiify-candle-chart] [data-part="crosshair"] {
    position: absolute;
    z-index: 3;
    inset: 0;
    inline-size: var(--candle-content-size, 100%);
    translate: calc(-1 * var(--candle-scroll-x, 0px)) 0;
    block-size: 100%;
    color: light-dark(oklch(52% 0.01 0deg), oklch(72% 0.01 0deg));
    pointer-events: none;
  }

  [data-uiify-candle-chart] [data-part="crosshair"]::before,
  [data-uiify-candle-chart] [data-part="crosshair"]::after {
    content: "";
    position: absolute;
    display: block;
    background: currentcolor;
  }

  [data-uiify-candle-chart] [data-part="crosshair"]::before {
    inset-block: 0;
    inset-inline-start: var(--candle-crosshair-x);
    inline-size: 1px;
    background-image: repeating-linear-gradient(
      to bottom,
      currentcolor 0 0.4rem,
      transparent 0.4rem 0.8rem
    );
    background-color: transparent;
  }

  [data-uiify-candle-chart] [data-part="crosshair"]::after {
    inset-block-start: calc(var(--candle-cursor-y, 50%) + 1rem);
    inset-inline: 0;
    block-size: 1px;
    background-image: repeating-linear-gradient(
      to right,
      currentcolor 0 0.4rem,
      transparent 0.4rem 0.8rem
    );
    background-color: transparent;
  }

  [data-uiify-candle-chart] [data-part="crosshair-marker"] {
    position: absolute;
    inset-block-start: calc(var(--candle-cursor-y, 50%) + 1rem);
    inset-inline-start: var(--candle-crosshair-x);
    font-size: 1rem;
    line-height: 1;
    transform: translate(-50%, -50%);
  }

  [data-uiify-candle-chart] [data-part="time-axis"] > [data-part="crosshair-time"] {
    inset-block-start: 0;
    inset-inline-start: var(--candle-crosshair-x);
    padding: 0.25rem 0.5rem;
    background: var(--candle-axis);
    color: Canvas;
    font-weight: 650;
    transform: translateX(-50%);
  }

  [data-uiify-candle-chart] [data-part="price-axis"] > [data-part="crosshair-price"] {
    inset-block-start: calc(var(--candle-cursor-y, 50%) + 1rem);
    inset-inline-end: 0;
    padding: 0.25rem 0.5rem;
    background: var(--candle-axis);
    color: Canvas;
    font-weight: 650;
    transform: translateY(-50%);
  }

  [data-uiify-candle-chart][data-interactive] [data-part="candle-hit"]:focus-visible {
    outline: 2px solid currentcolor;
    outline-offset: -2px;
  }

  [data-uiify-candle-chart] [data-part="price-axis"],
  [data-uiify-candle-chart] [data-part="time-axis"] {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  [data-uiify-candle-chart] [data-part="price-axis"] {
    position: relative;
    grid-column: 2;
    grid-row: 1;
    min-inline-size: 0;
  }

  [data-uiify-candle-chart] [data-part="price-axis"] > li {
    position: absolute;
    inset-inline: 0;
    inset-block-start: var(--candle-axis-y);
    overflow: hidden;
    color: var(--candle-axis);
    font-size: 0.65rem;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    text-align: end;
    text-overflow: ellipsis;
    white-space: nowrap;
    transform: translateY(-50%);
  }

  [data-uiify-candle-chart] [data-part="price-axis"] > li:first-child {
    transform: none;
  }

  [data-uiify-candle-chart] [data-part="price-axis"] > li:last-child {
    transform: translateY(-100%);
  }

  [data-uiify-candle-chart] [data-part="time-axis"] {
    position: relative;
    inset-block: 0;
    inline-size: var(--candle-content-size, 100%);
    translate: calc(-1 * var(--candle-scroll-x, 0px)) 0;
    min-inline-size: 0;
  }

  [data-uiify-candle-chart] [data-part="time-axis"] > li {
    position: absolute;
    inset-block-start: 0.375rem;
    inset-inline-start: var(--candle-axis-x);
    color: var(--candle-axis);
    font-size: 0.7rem;
    white-space: nowrap;
    transform: translateX(-50%);
  }

  [data-uiify-candle-chart] [data-part="time-axis"] > li:first-child {
    transform: none;
  }

  [data-uiify-candle-chart] [data-part="time-axis"] > li:last-child {
    transform: translateX(-100%);
  }

  [data-uiify-candle-chart] [data-part="time-axis"] > li:only-child {
    transform: translateX(-50%);
  }

  [data-uiify-candle-chart] [data-part="time-axis"] > li[data-part="crosshair-time"] {
    transform: translateX(-50%);
  }

  [data-uiify-candle-chart] [data-part="price-axis"] > li[data-part="crosshair-price"] {
    transform: translateY(-50%);
  }

  [data-uiify-candle-chart] > table {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
import { useEffect, useState } from "react";
import { CandleChart } from "@gunkin/uiify";
import { CandleChartClient } from "@gunkin/uiify/components/candle-chart/client";

const data = Array.from({ length: 100 }, (_, index) => {
  const open = Math.round(24000 + index * 38 + Math.sin(index / 4) * 420);
  const close = open + Math.round(Math.sin(index * 1.9) * 190);

  return {
    time: new Date(Date.UTC(2025, 7, 20 + index)).toISOString().slice(0, 10),
    open,
    high: Math.max(open, close) + 180,
    low: Math.min(open, close) - 160,
    close,
  };
});

export default function Example() {
  return (
    <>
      <CandleChart
        className={
          "[--candle-grid:color-mix(in_srgb,_currentcolor_10%,_transparent)] [--candle-down:oklch(64%_0.21_24deg)] [" +
          "--candle-flat:color-mix(in_srgb,_currentcolor_60%,_transparent)] [--candle-up:oklch(67%_0.14_166deg)] [--" +
          "candle-axis:var(--muted-foreground)] relative block [inline-size:100%] [min-block-size:21rem] [padding:1r" +
          "em_0.75rem_0.5rem] overflow-clip [overscroll-behavior:none] isolate [color-scheme:light_dark] bg-transpar" +
          "ent [color:light-dark(oklch(28%_0.04_165deg),_oklch(82%_0.04_165deg))] data-[interactive]:[touch-action:n" +
          "one] [&[data-interactive]_[data-part=scroll-viewport]]:[overscroll-behavior-inline:none] [&>[data-part=pl" +
          "ot]]:relative [&>[data-part=plot]]:grid [&>[data-part=plot]]:[grid-template-columns:minmax(0,_1fr)_4.5rem" +
          "] [&>[data-part=plot]]:[grid-template-rows:minmax(18rem,_1fr)_calc(1.5rem_+_var(--candle-scrollbar-size,_" +
          "0px))] [&>[data-part=plot]]:[gap:0_0.75rem] [&>[data-part=plot]]:[min-inline-size:0] [&>[data-part=plot]]" +
          ":[min-block-size:18rem] [&>[data-part=plot]]:[overscroll-behavior:none] [&_[data-part=scroll-viewport]]:[" +
          "grid-column:1] [&_[data-part=scroll-viewport]]:[grid-row:1_/_span_2] [&_[data-part=scroll-viewport]]:[min" +
          "-inline-size:0] [&_[data-part=scroll-viewport]]:[min-block-size:18rem] [&_[data-part=scroll-viewport]]:[o" +
          "verflow:auto_hidden] [&_[data-part=scroll-viewport]]:[container-type:inline-size] [&_[data-part=scroll-vi" +
          "ewport]]:[direction:rtl] [&_[data-part=canvas]]:grid [&_[data-part=canvas]]:[grid-template-rows:minmax(18" +
          "rem,_1fr)_1.5rem] [&_[data-part=canvas]]:[inline-size:calc(100%_*_var(--candle-scale))] [&_[data-part=can" +
          "vas]]:[min-inline-size:100%] [&_[data-part=canvas]]:[min-block-size:100%] [&_[data-part=canvas]]:[directi" +
          "on:ltr] [&_[data-part=candles]]:absolute [&_[data-part=candles]]:[inset-block:0] [&_[data-part=candles]]:" +
          "[inset-inline:auto_0] [&_[data-part=candles]]:[inline-size:100%] [&_[data-part=candles]]:m-0 [&_[data-par" +
          "t=candles]]:[padding:1rem_0.5rem] [&_[data-part=candles]]:list-none [&_[data-part=viewport]>[data-uiify-v" +
          "irtual-scroll]]:absolute [&_[data-part=viewport]>[data-uiify-virtual-scroll]]:inset-0 [&_[data-uiify-virt" +
          "ual-scroll]_[data-part=candle]]:[inset-block:1rem_auto] [&_[data-uiify-virtual-scroll]_[data-part=candle]" +
          "]:[block-size:calc(var(--candle-plot-height,_18rem)_-_2rem)] [&_[data-part=candles]]:[background-image:li" +
          "near-gradient(to_right,_var(--candle-grid)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle" +
          "-grid)_1px,_transparent_1px)] [&_[data-part=candles]]:[background-size:10%_100%,_100%_25%] [&_[data-part=" +
          "viewport]:has(>[data-uiify-virtual-scroll])]:[background-image:linear-gradient(to_right,_var(--candle-gri" +
          "d)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle-grid)_1px,_transparent_1px)] [&_[data-p" +
          "art=viewport]:has(>[data-uiify-virtual-scroll])]:[background-size:10%_100%,_100%_25%] [&_[data-part=viewp" +
          "ort]]:relative [&_[data-part=viewport]]:[grid-column:1] [&_[data-part=viewport]]:[grid-row:1] [&_[data-pa" +
          "rt=viewport]]:[min-inline-size:0] [&_[data-part=viewport]]:[min-block-size:18rem] [&_[data-part=viewport]" +
          "]:overflow-clip [&_[data-part=viewport]]:[overscroll-behavior:none] [&_[data-part=time-viewport]]:relativ" +
          "e [&_[data-part=time-viewport]]:[grid-column:1] [&_[data-part=time-viewport]]:[grid-row:2] [&_[data-part=" +
          "time-viewport]]:[min-inline-size:0] [&_[data-part=time-viewport]]:overflow-clip [&_[data-part=time-viewpo" +
          "rt]]:[overscroll-behavior:none] [&>figcaption]:absolute [&>figcaption]:z-[1] [&>figcaption]:[inset-block-" +
          "start:0.75rem] [&>figcaption]:[inset-inline-start:1rem] [&>figcaption]:text-muted-foreground [&>figcaptio" +
          "n]:[font-size:0.75rem] [&>figcaption]:[font-weight:650] [&>figcaption]:[letter-spacing:0.04em] [&>figcapt" +
          "ion]:[text-transform:uppercase] [&_[data-part=readout]]:absolute [&_[data-part=readout]]:z-[1] [&_[data-p" +
          "art=readout]]:[inset-block-start:0.75rem] [&_[data-part=readout]]:[inset-inline-end:1rem] [&_[data-part=r" +
          "eadout]]:flex [&_[data-part=readout]]:flex-wrap [&_[data-part=readout]]:[gap:0.375rem_0.625rem] [&_[data-" +
          "part=readout]]:items-baseline [&_[data-part=readout]]:[color:var(--candle-axis)] [&_[data-part=readout]]:" +
          "[font-size:0.7rem] [&_[data-part=readout]]:[font-variant-numeric:tabular-nums] [&_[data-part=readout]]:le" +
          "ading-none [&_[data-part=readout]]:whitespace-nowrap [&_[data-part=readout-time]]:[font-weight:650] [&_[d" +
          "ata-part=candle]]:absolute [&_[data-part=candle]]:[inset:1rem_0.5rem] [&_[data-part=candle]]:pointer-even" +
          "ts-none [&_[data-part=candle]]:[inset-inline-start:var(--candle-x)] [&_[data-part=candle]]:[inline-size:v" +
          "ar(--candle-slot)] [&_[data-part=candle]]:block [&_[data-part=candle]]:[color:var(--candle-flat)] [&_[dat" +
          "a-part=candle]]:list-none [&[data-interactive]_[data-part=candle]]:[pointer-events:auto] [&_[data-part=ca" +
          "ndle-hit]]:absolute [&_[data-part=candle-hit]]:z-[1] [&_[data-part=candle-hit]]:inset-0 [&_[data-part=can" +
          "dle-hit]]:[inline-size:100%] [&_[data-part=candle-hit]]:[block-size:100%] [&_[data-part=candle-hit]]:m-0 " +
          "[&_[data-part=candle-hit]]:p-0 [&_[data-part=candle-hit]]:border-0 [&_[data-part=candle-hit]]:border-curr" +
          "ent [&_[data-part=candle-hit]]:border-none [&_[data-part=candle-hit]]:appearance-none [&_[data-part=candl" +
          "e-hit]]:bg-transparent [&_[data-part=candle-hit]]:text-transparent [&_[data-part=candle-hit]]:[cursor:cro" +
          "sshair] [&_[data-part=candle-hit]]:[font-style:inherit] [&_[data-part=candle-hit]]:[font-variant:inherit]" +
          " [&_[data-part=candle-hit]]:[font-weight:inherit] [&_[data-part=candle-hit]]:[font-stretch:inherit] [&_[d" +
          "ata-part=candle-hit]]:text-[length:inherit] [&_[data-part=candle-hit]]:leading-[inherit] [&_[data-part=ca" +
          "ndle-hit]]:font-[family-name:inherit] [&_[data-part=candle]::before]:content-[''] [&_[data-part=candle]::" +
          "before]:absolute [&_[data-part=candle]::before]:block [&_[data-part=candle]::before]:[background:currentc" +
          "olor] [&_[data-part=candle]::after]:content-[''] [&_[data-part=candle]::after]:absolute [&_[data-part=can" +
          "dle]::after]:block [&_[data-part=candle]::after]:[background:currentcolor] [&_[data-part=candle]::before]" +
          ":[inset-block-start:var(--candle-wick-top)] [&_[data-part=candle]::before]:[inset-inline-start:50%] [&_[d" +
          "ata-part=candle]::before]:[inline-size:max(1px,_0.08em)] [&_[data-part=candle]::before]:[block-size:var(-" +
          "-candle-wick-height)] [&_[data-part=candle]::before]:[transform:translateX(-50%)] [&_[data-part=candle]::" +
          "after]:[inset-block-start:var(--candle-body-top)] [&_[data-part=candle]::after]:[inset-inline:17%] [&_[da" +
          "ta-part=candle]::after]:[block-size:var(--candle-body-height)] [&_[data-part=candle]::after]:[min-block-s" +
          "ize:1px] [&_[data-part=candle][data-direction=up]]:[color:var(--candle-up)] [&_[data-part=candle][data-di" +
          "rection=down]]:[color:var(--candle-down)] [&_[data-part=crosshair]]:absolute [&_[data-part=crosshair]]:z-" +
          "[3] [&_[data-part=crosshair]]:inset-0 [&_[data-part=crosshair]]:[inline-size:var(--candle-content-size,_1" +
          "00%)] [&_[data-part=crosshair]]:[translate:calc(-1_*_var(--candle-scroll-x,_0px))_0] [&_[data-part=crossh" +
          "air]]:[block-size:100%] [&_[data-part=crosshair]]:[color:light-dark(oklch(52%_0.01_0deg),_oklch(72%_0.01_" +
          "0deg))] [&_[data-part=crosshair]]:pointer-events-none [&_[data-part=crosshair]::before]:content-[''] [&_[" +
          "data-part=crosshair]::before]:absolute [&_[data-part=crosshair]::before]:block [&_[data-part=crosshair]::" +
          "before]:[background:currentcolor] [&_[data-part=crosshair]::after]:content-[''] [&_[data-part=crosshair]:" +
          ":after]:absolute [&_[data-part=crosshair]::after]:block [&_[data-part=crosshair]::after]:[background:curr" +
          "entcolor] [&_[data-part=crosshair]::before]:[inset-block:0] [&_[data-part=crosshair]::before]:[inset-inli" +
          "ne-start:var(--candle-crosshair-x)] [&_[data-part=crosshair]::before]:[inline-size:1px] [&_[data-part=cro" +
          "sshair]::before]:[background-image:repeating-linear-gradient(_to_bottom,_currentcolor_0_0.4rem,_transpare" +
          "nt_0.4rem_0.8rem_)] [&_[data-part=crosshair]::before]:bg-transparent [&_[data-part=crosshair]::after]:[in" +
          "set-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair]::after]:[inset-inline:" +
          "0] [&_[data-part=crosshair]::after]:[block-size:1px] [&_[data-part=crosshair]::after]:[background-image:r" +
          "epeating-linear-gradient(_to_right,_currentcolor_0_0.4rem,_transparent_0.4rem_0.8rem_)] [&_[data-part=cro" +
          "sshair]::after]:bg-transparent [&_[data-part=crosshair-marker]]:absolute [&_[data-part=crosshair-marker]]" +
          ":[inset-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair-marker]]:[inset-inl" +
          "ine-start:var(--candle-crosshair-x)] [&_[data-part=crosshair-marker]]:[font-size:1rem] [&_[data-part=cros" +
          "shair-marker]]:leading-none [&_[data-part=crosshair-marker]]:[transform:translate(-50%,_-50%)] [&_[data-p" +
          "art=time-axis]>[data-part=crosshair-time]]:[inset-block-start:0] [&_[data-part=time-axis]>[data-part=cros" +
          "shair-time]]:[inset-inline-start:var(--candle-crosshair-x)] [&_[data-part=time-axis]>[data-part=crosshair" +
          "-time]]:[padding:0.25rem_0.5rem] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[background:var(--c" +
          "andle-axis)] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[color:Canvas] [&_[data-part=time-axis]" +
          ">[data-part=crosshair-time]]:[font-weight:650] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[tran" +
          "sform:translateX(-50%)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-block-start:calc(va" +
          "r(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-inline-e" +
          "nd:0] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[padding:0.25rem_0.5rem] [&_[data-part=price" +
          "-axis]>[data-part=crosshair-price]]:[background:var(--candle-axis)] [&_[data-part=price-axis]>[data-part=" +
          "crosshair-price]]:[color:Canvas] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[font-weight:650]" +
          " [&_[data-part=price-axis]>[data-part=crosshair-price]]:[transform:translateY(-50%)] [&[data-interactive]" +
          "_[data-part=candle-hit]:focus-visible]:[outline:2px_solid_currentcolor] [&[data-interactive]_[data-part=c" +
          "andle-hit]:focus-visible]:[outline-offset:-2px] [&_[data-part=price-axis]]:m-0 [&_[data-part=price-axis]]" +
          ":p-0 [&_[data-part=price-axis]]:list-none [&_[data-part=time-axis]]:m-0 [&_[data-part=time-axis]]:p-0 [&_" +
          "[data-part=time-axis]]:list-none [&_[data-part=price-axis]]:relative [&_[data-part=price-axis]]:[grid-col" +
          "umn:2] [&_[data-part=price-axis]]:[grid-row:1] [&_[data-part=price-axis]]:[min-inline-size:0] [&_[data-pa" +
          "rt=price-axis]>li]:absolute [&_[data-part=price-axis]>li]:[inset-inline:0] [&_[data-part=price-axis]>li]:" +
          "[inset-block-start:var(--candle-axis-y)] [&_[data-part=price-axis]>li]:overflow-hidden [&_[data-part=pric" +
          "e-axis]>li]:[color:var(--candle-axis)] [&_[data-part=price-axis]>li]:[font-size:0.65rem] [&_[data-part=pr" +
          "ice-axis]>li]:[font-variant-numeric:tabular-nums] [&_[data-part=price-axis]>li]:leading-none [&_[data-par" +
          "t=price-axis]>li]:text-end [&_[data-part=price-axis]>li]:[text-overflow:ellipsis] [&_[data-part=price-axi" +
          "s]>li]:whitespace-nowrap [&_[data-part=price-axis]>li]:[transform:translateY(-50%)] [&_[data-part=price-a" +
          "xis]>li:first-child]:[transform:none] [&_[data-part=price-axis]>li:last-child]:[transform:translateY(-100" +
          "%)] [&_[data-part=time-axis]]:relative [&_[data-part=time-axis]]:[inset-block:0] [&_[data-part=time-axis]" +
          "]:[inline-size:var(--candle-content-size,_100%)] [&_[data-part=time-axis]]:[translate:calc(-1_*_var(--can" +
          "dle-scroll-x,_0px))_0] [&_[data-part=time-axis]]:[min-inline-size:0] [&_[data-part=time-axis]>li]:absolut" +
          "e [&_[data-part=time-axis]>li]:[inset-block-start:0.375rem] [&_[data-part=time-axis]>li]:[inset-inline-st" +
          "art:var(--candle-axis-x)] [&_[data-part=time-axis]>li]:[color:var(--candle-axis)] [&_[data-part=time-axis" +
          "]>li]:[font-size:0.7rem] [&_[data-part=time-axis]>li]:whitespace-nowrap [&_[data-part=time-axis]>li]:[tra" +
          "nsform:translateX(-50%)] [&_[data-part=time-axis]>li:first-child]:[transform:none] [&_[data-part=time-axi" +
          "s]>li:last-child]:[transform:translateX(-100%)] [&_[data-part=time-axis]>li:only-child]:[transform:transl" +
          "ateX(-50%)] [&_[data-part=time-axis]>li[data-part=crosshair-time]]:[transform:translateX(-50%)] [&_[data-" +
          "part=price-axis]>li[data-part=crosshair-price]]:[transform:translateY(-50%)] [&>table]:absolute [&>table]" +
          ":[inline-size:1px] [&>table]:[block-size:1px] [&>table]:overflow-hidden [&>table]:[clip-path:inset(50%)] " +
          "[&>table]:whitespace-nowrap"
        }
        data={data}
        aria-label="BTC / USD daily candles"
      />
      <CandleChartClient
        className={
          "[--candle-grid:color-mix(in_srgb,_currentcolor_10%,_transparent)] [--candle-down:oklch(64%_0.21_24deg)] [" +
          "--candle-flat:color-mix(in_srgb,_currentcolor_60%,_transparent)] [--candle-up:oklch(67%_0.14_166deg)] [--" +
          "candle-axis:var(--muted-foreground)] relative block [inline-size:100%] [min-block-size:21rem] [padding:1r" +
          "em_0.75rem_0.5rem] overflow-clip [overscroll-behavior:none] isolate [color-scheme:light_dark] bg-transpar" +
          "ent [color:light-dark(oklch(28%_0.04_165deg),_oklch(82%_0.04_165deg))] data-[interactive]:[touch-action:n" +
          "one] [&[data-interactive]_[data-part=scroll-viewport]]:[overscroll-behavior-inline:none] [&>[data-part=pl" +
          "ot]]:relative [&>[data-part=plot]]:grid [&>[data-part=plot]]:[grid-template-columns:minmax(0,_1fr)_4.5rem" +
          "] [&>[data-part=plot]]:[grid-template-rows:minmax(18rem,_1fr)_calc(1.5rem_+_var(--candle-scrollbar-size,_" +
          "0px))] [&>[data-part=plot]]:[gap:0_0.75rem] [&>[data-part=plot]]:[min-inline-size:0] [&>[data-part=plot]]" +
          ":[min-block-size:18rem] [&>[data-part=plot]]:[overscroll-behavior:none] [&_[data-part=scroll-viewport]]:[" +
          "grid-column:1] [&_[data-part=scroll-viewport]]:[grid-row:1_/_span_2] [&_[data-part=scroll-viewport]]:[min" +
          "-inline-size:0] [&_[data-part=scroll-viewport]]:[min-block-size:18rem] [&_[data-part=scroll-viewport]]:[o" +
          "verflow:auto_hidden] [&_[data-part=scroll-viewport]]:[container-type:inline-size] [&_[data-part=scroll-vi" +
          "ewport]]:[direction:rtl] [&_[data-part=canvas]]:grid [&_[data-part=canvas]]:[grid-template-rows:minmax(18" +
          "rem,_1fr)_1.5rem] [&_[data-part=canvas]]:[inline-size:calc(100%_*_var(--candle-scale))] [&_[data-part=can" +
          "vas]]:[min-inline-size:100%] [&_[data-part=canvas]]:[min-block-size:100%] [&_[data-part=canvas]]:[directi" +
          "on:ltr] [&_[data-part=candles]]:absolute [&_[data-part=candles]]:[inset-block:0] [&_[data-part=candles]]:" +
          "[inset-inline:auto_0] [&_[data-part=candles]]:[inline-size:100%] [&_[data-part=candles]]:m-0 [&_[data-par" +
          "t=candles]]:[padding:1rem_0.5rem] [&_[data-part=candles]]:list-none [&_[data-part=viewport]>[data-uiify-v" +
          "irtual-scroll]]:absolute [&_[data-part=viewport]>[data-uiify-virtual-scroll]]:inset-0 [&_[data-uiify-virt" +
          "ual-scroll]_[data-part=candle]]:[inset-block:1rem_auto] [&_[data-uiify-virtual-scroll]_[data-part=candle]" +
          "]:[block-size:calc(var(--candle-plot-height,_18rem)_-_2rem)] [&_[data-part=candles]]:[background-image:li" +
          "near-gradient(to_right,_var(--candle-grid)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle" +
          "-grid)_1px,_transparent_1px)] [&_[data-part=candles]]:[background-size:10%_100%,_100%_25%] [&_[data-part=" +
          "viewport]:has(>[data-uiify-virtual-scroll])]:[background-image:linear-gradient(to_right,_var(--candle-gri" +
          "d)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle-grid)_1px,_transparent_1px)] [&_[data-p" +
          "art=viewport]:has(>[data-uiify-virtual-scroll])]:[background-size:10%_100%,_100%_25%] [&_[data-part=viewp" +
          "ort]]:relative [&_[data-part=viewport]]:[grid-column:1] [&_[data-part=viewport]]:[grid-row:1] [&_[data-pa" +
          "rt=viewport]]:[min-inline-size:0] [&_[data-part=viewport]]:[min-block-size:18rem] [&_[data-part=viewport]" +
          "]:overflow-clip [&_[data-part=viewport]]:[overscroll-behavior:none] [&_[data-part=time-viewport]]:relativ" +
          "e [&_[data-part=time-viewport]]:[grid-column:1] [&_[data-part=time-viewport]]:[grid-row:2] [&_[data-part=" +
          "time-viewport]]:[min-inline-size:0] [&_[data-part=time-viewport]]:overflow-clip [&_[data-part=time-viewpo" +
          "rt]]:[overscroll-behavior:none] [&>figcaption]:absolute [&>figcaption]:z-[1] [&>figcaption]:[inset-block-" +
          "start:0.75rem] [&>figcaption]:[inset-inline-start:1rem] [&>figcaption]:text-muted-foreground [&>figcaptio" +
          "n]:[font-size:0.75rem] [&>figcaption]:[font-weight:650] [&>figcaption]:[letter-spacing:0.04em] [&>figcapt" +
          "ion]:[text-transform:uppercase] [&_[data-part=readout]]:absolute [&_[data-part=readout]]:z-[1] [&_[data-p" +
          "art=readout]]:[inset-block-start:0.75rem] [&_[data-part=readout]]:[inset-inline-end:1rem] [&_[data-part=r" +
          "eadout]]:flex [&_[data-part=readout]]:flex-wrap [&_[data-part=readout]]:[gap:0.375rem_0.625rem] [&_[data-" +
          "part=readout]]:items-baseline [&_[data-part=readout]]:[color:var(--candle-axis)] [&_[data-part=readout]]:" +
          "[font-size:0.7rem] [&_[data-part=readout]]:[font-variant-numeric:tabular-nums] [&_[data-part=readout]]:le" +
          "ading-none [&_[data-part=readout]]:whitespace-nowrap [&_[data-part=readout-time]]:[font-weight:650] [&_[d" +
          "ata-part=candle]]:absolute [&_[data-part=candle]]:[inset:1rem_0.5rem] [&_[data-part=candle]]:pointer-even" +
          "ts-none [&_[data-part=candle]]:[inset-inline-start:var(--candle-x)] [&_[data-part=candle]]:[inline-size:v" +
          "ar(--candle-slot)] [&_[data-part=candle]]:block [&_[data-part=candle]]:[color:var(--candle-flat)] [&_[dat" +
          "a-part=candle]]:list-none [&[data-interactive]_[data-part=candle]]:[pointer-events:auto] [&_[data-part=ca" +
          "ndle-hit]]:absolute [&_[data-part=candle-hit]]:z-[1] [&_[data-part=candle-hit]]:inset-0 [&_[data-part=can" +
          "dle-hit]]:[inline-size:100%] [&_[data-part=candle-hit]]:[block-size:100%] [&_[data-part=candle-hit]]:m-0 " +
          "[&_[data-part=candle-hit]]:p-0 [&_[data-part=candle-hit]]:border-0 [&_[data-part=candle-hit]]:border-curr" +
          "ent [&_[data-part=candle-hit]]:border-none [&_[data-part=candle-hit]]:appearance-none [&_[data-part=candl" +
          "e-hit]]:bg-transparent [&_[data-part=candle-hit]]:text-transparent [&_[data-part=candle-hit]]:[cursor:cro" +
          "sshair] [&_[data-part=candle-hit]]:[font-style:inherit] [&_[data-part=candle-hit]]:[font-variant:inherit]" +
          " [&_[data-part=candle-hit]]:[font-weight:inherit] [&_[data-part=candle-hit]]:[font-stretch:inherit] [&_[d" +
          "ata-part=candle-hit]]:text-[length:inherit] [&_[data-part=candle-hit]]:leading-[inherit] [&_[data-part=ca" +
          "ndle-hit]]:font-[family-name:inherit] [&_[data-part=candle]::before]:content-[''] [&_[data-part=candle]::" +
          "before]:absolute [&_[data-part=candle]::before]:block [&_[data-part=candle]::before]:[background:currentc" +
          "olor] [&_[data-part=candle]::after]:content-[''] [&_[data-part=candle]::after]:absolute [&_[data-part=can" +
          "dle]::after]:block [&_[data-part=candle]::after]:[background:currentcolor] [&_[data-part=candle]::before]" +
          ":[inset-block-start:var(--candle-wick-top)] [&_[data-part=candle]::before]:[inset-inline-start:50%] [&_[d" +
          "ata-part=candle]::before]:[inline-size:max(1px,_0.08em)] [&_[data-part=candle]::before]:[block-size:var(-" +
          "-candle-wick-height)] [&_[data-part=candle]::before]:[transform:translateX(-50%)] [&_[data-part=candle]::" +
          "after]:[inset-block-start:var(--candle-body-top)] [&_[data-part=candle]::after]:[inset-inline:17%] [&_[da" +
          "ta-part=candle]::after]:[block-size:var(--candle-body-height)] [&_[data-part=candle]::after]:[min-block-s" +
          "ize:1px] [&_[data-part=candle][data-direction=up]]:[color:var(--candle-up)] [&_[data-part=candle][data-di" +
          "rection=down]]:[color:var(--candle-down)] [&_[data-part=crosshair]]:absolute [&_[data-part=crosshair]]:z-" +
          "[3] [&_[data-part=crosshair]]:inset-0 [&_[data-part=crosshair]]:[inline-size:var(--candle-content-size,_1" +
          "00%)] [&_[data-part=crosshair]]:[translate:calc(-1_*_var(--candle-scroll-x,_0px))_0] [&_[data-part=crossh" +
          "air]]:[block-size:100%] [&_[data-part=crosshair]]:[color:light-dark(oklch(52%_0.01_0deg),_oklch(72%_0.01_" +
          "0deg))] [&_[data-part=crosshair]]:pointer-events-none [&_[data-part=crosshair]::before]:content-[''] [&_[" +
          "data-part=crosshair]::before]:absolute [&_[data-part=crosshair]::before]:block [&_[data-part=crosshair]::" +
          "before]:[background:currentcolor] [&_[data-part=crosshair]::after]:content-[''] [&_[data-part=crosshair]:" +
          ":after]:absolute [&_[data-part=crosshair]::after]:block [&_[data-part=crosshair]::after]:[background:curr" +
          "entcolor] [&_[data-part=crosshair]::before]:[inset-block:0] [&_[data-part=crosshair]::before]:[inset-inli" +
          "ne-start:var(--candle-crosshair-x)] [&_[data-part=crosshair]::before]:[inline-size:1px] [&_[data-part=cro" +
          "sshair]::before]:[background-image:repeating-linear-gradient(_to_bottom,_currentcolor_0_0.4rem,_transpare" +
          "nt_0.4rem_0.8rem_)] [&_[data-part=crosshair]::before]:bg-transparent [&_[data-part=crosshair]::after]:[in" +
          "set-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair]::after]:[inset-inline:" +
          "0] [&_[data-part=crosshair]::after]:[block-size:1px] [&_[data-part=crosshair]::after]:[background-image:r" +
          "epeating-linear-gradient(_to_right,_currentcolor_0_0.4rem,_transparent_0.4rem_0.8rem_)] [&_[data-part=cro" +
          "sshair]::after]:bg-transparent [&_[data-part=crosshair-marker]]:absolute [&_[data-part=crosshair-marker]]" +
          ":[inset-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair-marker]]:[inset-inl" +
          "ine-start:var(--candle-crosshair-x)] [&_[data-part=crosshair-marker]]:[font-size:1rem] [&_[data-part=cros" +
          "shair-marker]]:leading-none [&_[data-part=crosshair-marker]]:[transform:translate(-50%,_-50%)] [&_[data-p" +
          "art=time-axis]>[data-part=crosshair-time]]:[inset-block-start:0] [&_[data-part=time-axis]>[data-part=cros" +
          "shair-time]]:[inset-inline-start:var(--candle-crosshair-x)] [&_[data-part=time-axis]>[data-part=crosshair" +
          "-time]]:[padding:0.25rem_0.5rem] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[background:var(--c" +
          "andle-axis)] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[color:Canvas] [&_[data-part=time-axis]" +
          ">[data-part=crosshair-time]]:[font-weight:650] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[tran" +
          "sform:translateX(-50%)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-block-start:calc(va" +
          "r(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-inline-e" +
          "nd:0] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[padding:0.25rem_0.5rem] [&_[data-part=price" +
          "-axis]>[data-part=crosshair-price]]:[background:var(--candle-axis)] [&_[data-part=price-axis]>[data-part=" +
          "crosshair-price]]:[color:Canvas] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[font-weight:650]" +
          " [&_[data-part=price-axis]>[data-part=crosshair-price]]:[transform:translateY(-50%)] [&[data-interactive]" +
          "_[data-part=candle-hit]:focus-visible]:[outline:2px_solid_currentcolor] [&[data-interactive]_[data-part=c" +
          "andle-hit]:focus-visible]:[outline-offset:-2px] [&_[data-part=price-axis]]:m-0 [&_[data-part=price-axis]]" +
          ":p-0 [&_[data-part=price-axis]]:list-none [&_[data-part=time-axis]]:m-0 [&_[data-part=time-axis]]:p-0 [&_" +
          "[data-part=time-axis]]:list-none [&_[data-part=price-axis]]:relative [&_[data-part=price-axis]]:[grid-col" +
          "umn:2] [&_[data-part=price-axis]]:[grid-row:1] [&_[data-part=price-axis]]:[min-inline-size:0] [&_[data-pa" +
          "rt=price-axis]>li]:absolute [&_[data-part=price-axis]>li]:[inset-inline:0] [&_[data-part=price-axis]>li]:" +
          "[inset-block-start:var(--candle-axis-y)] [&_[data-part=price-axis]>li]:overflow-hidden [&_[data-part=pric" +
          "e-axis]>li]:[color:var(--candle-axis)] [&_[data-part=price-axis]>li]:[font-size:0.65rem] [&_[data-part=pr" +
          "ice-axis]>li]:[font-variant-numeric:tabular-nums] [&_[data-part=price-axis]>li]:leading-none [&_[data-par" +
          "t=price-axis]>li]:text-end [&_[data-part=price-axis]>li]:[text-overflow:ellipsis] [&_[data-part=price-axi" +
          "s]>li]:whitespace-nowrap [&_[data-part=price-axis]>li]:[transform:translateY(-50%)] [&_[data-part=price-a" +
          "xis]>li:first-child]:[transform:none] [&_[data-part=price-axis]>li:last-child]:[transform:translateY(-100" +
          "%)] [&_[data-part=time-axis]]:relative [&_[data-part=time-axis]]:[inset-block:0] [&_[data-part=time-axis]" +
          "]:[inline-size:var(--candle-content-size,_100%)] [&_[data-part=time-axis]]:[translate:calc(-1_*_var(--can" +
          "dle-scroll-x,_0px))_0] [&_[data-part=time-axis]]:[min-inline-size:0] [&_[data-part=time-axis]>li]:absolut" +
          "e [&_[data-part=time-axis]>li]:[inset-block-start:0.375rem] [&_[data-part=time-axis]>li]:[inset-inline-st" +
          "art:var(--candle-axis-x)] [&_[data-part=time-axis]>li]:[color:var(--candle-axis)] [&_[data-part=time-axis" +
          "]>li]:[font-size:0.7rem] [&_[data-part=time-axis]>li]:whitespace-nowrap [&_[data-part=time-axis]>li]:[tra" +
          "nsform:translateX(-50%)] [&_[data-part=time-axis]>li:first-child]:[transform:none] [&_[data-part=time-axi" +
          "s]>li:last-child]:[transform:translateX(-100%)] [&_[data-part=time-axis]>li:only-child]:[transform:transl" +
          "ateX(-50%)] [&_[data-part=time-axis]>li[data-part=crosshair-time]]:[transform:translateX(-50%)] [&_[data-" +
          "part=price-axis]>li[data-part=crosshair-price]]:[transform:translateY(-50%)] [&>table]:absolute [&>table]" +
          ":[inline-size:1px] [&>table]:[block-size:1px] [&>table]:overflow-hidden [&>table]:[clip-path:inset(50%)] " +
          "[&>table]:whitespace-nowrap"
        }
        data={data}
        aria-label="Interactive BTC / USD daily candles"
      />
      <LiveChart />
    </>
  );
}

function LiveChart() {
  const [candles, setCandles] = useState(data);
  const [running, setRunning] = useState(false);

  useEffect(() => {
    if (!running) return;
    const timer = setInterval(() => {
      setCandles((current) => {
        const last = current.at(-1);
        if (!last) return current;
        const close = Math.round(last.close * (1 + (Math.random() - 0.5) * 0.004));
        const next = {
          time: String(current.length),
          open: last.close,
          high: Math.max(last.close, close),
          low: Math.min(last.close, close),
          close,
        };
        return [...current, next];
      });
    }, 1000);
    return () => clearInterval(timer);
  }, [running]);

  return (
    <>
      <button type="button" onClick={() => setRunning((value) => !value)}>
        {running ? "Stop" : "Start"}
      </button>
      {/* All candles, virtualized; 20 fit the viewport and new ones stay in view at the end. */}
      <CandleChartClient
        className={
          "[--candle-grid:color-mix(in_srgb,_currentcolor_10%,_transparent)] [--candle-down:oklch(64%_0.21_24deg)] [" +
          "--candle-flat:color-mix(in_srgb,_currentcolor_60%,_transparent)] [--candle-up:oklch(67%_0.14_166deg)] [--" +
          "candle-axis:var(--muted-foreground)] relative block [inline-size:100%] [min-block-size:21rem] [padding:1r" +
          "em_0.75rem_0.5rem] overflow-clip [overscroll-behavior:none] isolate [color-scheme:light_dark] bg-transpar" +
          "ent [color:light-dark(oklch(28%_0.04_165deg),_oklch(82%_0.04_165deg))] data-[interactive]:[touch-action:n" +
          "one] [&[data-interactive]_[data-part=scroll-viewport]]:[overscroll-behavior-inline:none] [&>[data-part=pl" +
          "ot]]:relative [&>[data-part=plot]]:grid [&>[data-part=plot]]:[grid-template-columns:minmax(0,_1fr)_4.5rem" +
          "] [&>[data-part=plot]]:[grid-template-rows:minmax(18rem,_1fr)_calc(1.5rem_+_var(--candle-scrollbar-size,_" +
          "0px))] [&>[data-part=plot]]:[gap:0_0.75rem] [&>[data-part=plot]]:[min-inline-size:0] [&>[data-part=plot]]" +
          ":[min-block-size:18rem] [&>[data-part=plot]]:[overscroll-behavior:none] [&_[data-part=scroll-viewport]]:[" +
          "grid-column:1] [&_[data-part=scroll-viewport]]:[grid-row:1_/_span_2] [&_[data-part=scroll-viewport]]:[min" +
          "-inline-size:0] [&_[data-part=scroll-viewport]]:[min-block-size:18rem] [&_[data-part=scroll-viewport]]:[o" +
          "verflow:auto_hidden] [&_[data-part=scroll-viewport]]:[container-type:inline-size] [&_[data-part=scroll-vi" +
          "ewport]]:[direction:rtl] [&_[data-part=canvas]]:grid [&_[data-part=canvas]]:[grid-template-rows:minmax(18" +
          "rem,_1fr)_1.5rem] [&_[data-part=canvas]]:[inline-size:calc(100%_*_var(--candle-scale))] [&_[data-part=can" +
          "vas]]:[min-inline-size:100%] [&_[data-part=canvas]]:[min-block-size:100%] [&_[data-part=canvas]]:[directi" +
          "on:ltr] [&_[data-part=candles]]:absolute [&_[data-part=candles]]:[inset-block:0] [&_[data-part=candles]]:" +
          "[inset-inline:auto_0] [&_[data-part=candles]]:[inline-size:100%] [&_[data-part=candles]]:m-0 [&_[data-par" +
          "t=candles]]:[padding:1rem_0.5rem] [&_[data-part=candles]]:list-none [&_[data-part=viewport]>[data-uiify-v" +
          "irtual-scroll]]:absolute [&_[data-part=viewport]>[data-uiify-virtual-scroll]]:inset-0 [&_[data-uiify-virt" +
          "ual-scroll]_[data-part=candle]]:[inset-block:1rem_auto] [&_[data-uiify-virtual-scroll]_[data-part=candle]" +
          "]:[block-size:calc(var(--candle-plot-height,_18rem)_-_2rem)] [&_[data-part=candles]]:[background-image:li" +
          "near-gradient(to_right,_var(--candle-grid)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle" +
          "-grid)_1px,_transparent_1px)] [&_[data-part=candles]]:[background-size:10%_100%,_100%_25%] [&_[data-part=" +
          "viewport]:has(>[data-uiify-virtual-scroll])]:[background-image:linear-gradient(to_right,_var(--candle-gri" +
          "d)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle-grid)_1px,_transparent_1px)] [&_[data-p" +
          "art=viewport]:has(>[data-uiify-virtual-scroll])]:[background-size:10%_100%,_100%_25%] [&_[data-part=viewp" +
          "ort]]:relative [&_[data-part=viewport]]:[grid-column:1] [&_[data-part=viewport]]:[grid-row:1] [&_[data-pa" +
          "rt=viewport]]:[min-inline-size:0] [&_[data-part=viewport]]:[min-block-size:18rem] [&_[data-part=viewport]" +
          "]:overflow-clip [&_[data-part=viewport]]:[overscroll-behavior:none] [&_[data-part=time-viewport]]:relativ" +
          "e [&_[data-part=time-viewport]]:[grid-column:1] [&_[data-part=time-viewport]]:[grid-row:2] [&_[data-part=" +
          "time-viewport]]:[min-inline-size:0] [&_[data-part=time-viewport]]:overflow-clip [&_[data-part=time-viewpo" +
          "rt]]:[overscroll-behavior:none] [&>figcaption]:absolute [&>figcaption]:z-[1] [&>figcaption]:[inset-block-" +
          "start:0.75rem] [&>figcaption]:[inset-inline-start:1rem] [&>figcaption]:text-muted-foreground [&>figcaptio" +
          "n]:[font-size:0.75rem] [&>figcaption]:[font-weight:650] [&>figcaption]:[letter-spacing:0.04em] [&>figcapt" +
          "ion]:[text-transform:uppercase] [&_[data-part=readout]]:absolute [&_[data-part=readout]]:z-[1] [&_[data-p" +
          "art=readout]]:[inset-block-start:0.75rem] [&_[data-part=readout]]:[inset-inline-end:1rem] [&_[data-part=r" +
          "eadout]]:flex [&_[data-part=readout]]:flex-wrap [&_[data-part=readout]]:[gap:0.375rem_0.625rem] [&_[data-" +
          "part=readout]]:items-baseline [&_[data-part=readout]]:[color:var(--candle-axis)] [&_[data-part=readout]]:" +
          "[font-size:0.7rem] [&_[data-part=readout]]:[font-variant-numeric:tabular-nums] [&_[data-part=readout]]:le" +
          "ading-none [&_[data-part=readout]]:whitespace-nowrap [&_[data-part=readout-time]]:[font-weight:650] [&_[d" +
          "ata-part=candle]]:absolute [&_[data-part=candle]]:[inset:1rem_0.5rem] [&_[data-part=candle]]:pointer-even" +
          "ts-none [&_[data-part=candle]]:[inset-inline-start:var(--candle-x)] [&_[data-part=candle]]:[inline-size:v" +
          "ar(--candle-slot)] [&_[data-part=candle]]:block [&_[data-part=candle]]:[color:var(--candle-flat)] [&_[dat" +
          "a-part=candle]]:list-none [&[data-interactive]_[data-part=candle]]:[pointer-events:auto] [&_[data-part=ca" +
          "ndle-hit]]:absolute [&_[data-part=candle-hit]]:z-[1] [&_[data-part=candle-hit]]:inset-0 [&_[data-part=can" +
          "dle-hit]]:[inline-size:100%] [&_[data-part=candle-hit]]:[block-size:100%] [&_[data-part=candle-hit]]:m-0 " +
          "[&_[data-part=candle-hit]]:p-0 [&_[data-part=candle-hit]]:border-0 [&_[data-part=candle-hit]]:border-curr" +
          "ent [&_[data-part=candle-hit]]:border-none [&_[data-part=candle-hit]]:appearance-none [&_[data-part=candl" +
          "e-hit]]:bg-transparent [&_[data-part=candle-hit]]:text-transparent [&_[data-part=candle-hit]]:[cursor:cro" +
          "sshair] [&_[data-part=candle-hit]]:[font-style:inherit] [&_[data-part=candle-hit]]:[font-variant:inherit]" +
          " [&_[data-part=candle-hit]]:[font-weight:inherit] [&_[data-part=candle-hit]]:[font-stretch:inherit] [&_[d" +
          "ata-part=candle-hit]]:text-[length:inherit] [&_[data-part=candle-hit]]:leading-[inherit] [&_[data-part=ca" +
          "ndle-hit]]:font-[family-name:inherit] [&_[data-part=candle]::before]:content-[''] [&_[data-part=candle]::" +
          "before]:absolute [&_[data-part=candle]::before]:block [&_[data-part=candle]::before]:[background:currentc" +
          "olor] [&_[data-part=candle]::after]:content-[''] [&_[data-part=candle]::after]:absolute [&_[data-part=can" +
          "dle]::after]:block [&_[data-part=candle]::after]:[background:currentcolor] [&_[data-part=candle]::before]" +
          ":[inset-block-start:var(--candle-wick-top)] [&_[data-part=candle]::before]:[inset-inline-start:50%] [&_[d" +
          "ata-part=candle]::before]:[inline-size:max(1px,_0.08em)] [&_[data-part=candle]::before]:[block-size:var(-" +
          "-candle-wick-height)] [&_[data-part=candle]::before]:[transform:translateX(-50%)] [&_[data-part=candle]::" +
          "after]:[inset-block-start:var(--candle-body-top)] [&_[data-part=candle]::after]:[inset-inline:17%] [&_[da" +
          "ta-part=candle]::after]:[block-size:var(--candle-body-height)] [&_[data-part=candle]::after]:[min-block-s" +
          "ize:1px] [&_[data-part=candle][data-direction=up]]:[color:var(--candle-up)] [&_[data-part=candle][data-di" +
          "rection=down]]:[color:var(--candle-down)] [&_[data-part=crosshair]]:absolute [&_[data-part=crosshair]]:z-" +
          "[3] [&_[data-part=crosshair]]:inset-0 [&_[data-part=crosshair]]:[inline-size:var(--candle-content-size,_1" +
          "00%)] [&_[data-part=crosshair]]:[translate:calc(-1_*_var(--candle-scroll-x,_0px))_0] [&_[data-part=crossh" +
          "air]]:[block-size:100%] [&_[data-part=crosshair]]:[color:light-dark(oklch(52%_0.01_0deg),_oklch(72%_0.01_" +
          "0deg))] [&_[data-part=crosshair]]:pointer-events-none [&_[data-part=crosshair]::before]:content-[''] [&_[" +
          "data-part=crosshair]::before]:absolute [&_[data-part=crosshair]::before]:block [&_[data-part=crosshair]::" +
          "before]:[background:currentcolor] [&_[data-part=crosshair]::after]:content-[''] [&_[data-part=crosshair]:" +
          ":after]:absolute [&_[data-part=crosshair]::after]:block [&_[data-part=crosshair]::after]:[background:curr" +
          "entcolor] [&_[data-part=crosshair]::before]:[inset-block:0] [&_[data-part=crosshair]::before]:[inset-inli" +
          "ne-start:var(--candle-crosshair-x)] [&_[data-part=crosshair]::before]:[inline-size:1px] [&_[data-part=cro" +
          "sshair]::before]:[background-image:repeating-linear-gradient(_to_bottom,_currentcolor_0_0.4rem,_transpare" +
          "nt_0.4rem_0.8rem_)] [&_[data-part=crosshair]::before]:bg-transparent [&_[data-part=crosshair]::after]:[in" +
          "set-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair]::after]:[inset-inline:" +
          "0] [&_[data-part=crosshair]::after]:[block-size:1px] [&_[data-part=crosshair]::after]:[background-image:r" +
          "epeating-linear-gradient(_to_right,_currentcolor_0_0.4rem,_transparent_0.4rem_0.8rem_)] [&_[data-part=cro" +
          "sshair]::after]:bg-transparent [&_[data-part=crosshair-marker]]:absolute [&_[data-part=crosshair-marker]]" +
          ":[inset-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair-marker]]:[inset-inl" +
          "ine-start:var(--candle-crosshair-x)] [&_[data-part=crosshair-marker]]:[font-size:1rem] [&_[data-part=cros" +
          "shair-marker]]:leading-none [&_[data-part=crosshair-marker]]:[transform:translate(-50%,_-50%)] [&_[data-p" +
          "art=time-axis]>[data-part=crosshair-time]]:[inset-block-start:0] [&_[data-part=time-axis]>[data-part=cros" +
          "shair-time]]:[inset-inline-start:var(--candle-crosshair-x)] [&_[data-part=time-axis]>[data-part=crosshair" +
          "-time]]:[padding:0.25rem_0.5rem] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[background:var(--c" +
          "andle-axis)] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[color:Canvas] [&_[data-part=time-axis]" +
          ">[data-part=crosshair-time]]:[font-weight:650] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[tran" +
          "sform:translateX(-50%)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-block-start:calc(va" +
          "r(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-inline-e" +
          "nd:0] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[padding:0.25rem_0.5rem] [&_[data-part=price" +
          "-axis]>[data-part=crosshair-price]]:[background:var(--candle-axis)] [&_[data-part=price-axis]>[data-part=" +
          "crosshair-price]]:[color:Canvas] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[font-weight:650]" +
          " [&_[data-part=price-axis]>[data-part=crosshair-price]]:[transform:translateY(-50%)] [&[data-interactive]" +
          "_[data-part=candle-hit]:focus-visible]:[outline:2px_solid_currentcolor] [&[data-interactive]_[data-part=c" +
          "andle-hit]:focus-visible]:[outline-offset:-2px] [&_[data-part=price-axis]]:m-0 [&_[data-part=price-axis]]" +
          ":p-0 [&_[data-part=price-axis]]:list-none [&_[data-part=time-axis]]:m-0 [&_[data-part=time-axis]]:p-0 [&_" +
          "[data-part=time-axis]]:list-none [&_[data-part=price-axis]]:relative [&_[data-part=price-axis]]:[grid-col" +
          "umn:2] [&_[data-part=price-axis]]:[grid-row:1] [&_[data-part=price-axis]]:[min-inline-size:0] [&_[data-pa" +
          "rt=price-axis]>li]:absolute [&_[data-part=price-axis]>li]:[inset-inline:0] [&_[data-part=price-axis]>li]:" +
          "[inset-block-start:var(--candle-axis-y)] [&_[data-part=price-axis]>li]:overflow-hidden [&_[data-part=pric" +
          "e-axis]>li]:[color:var(--candle-axis)] [&_[data-part=price-axis]>li]:[font-size:0.65rem] [&_[data-part=pr" +
          "ice-axis]>li]:[font-variant-numeric:tabular-nums] [&_[data-part=price-axis]>li]:leading-none [&_[data-par" +
          "t=price-axis]>li]:text-end [&_[data-part=price-axis]>li]:[text-overflow:ellipsis] [&_[data-part=price-axi" +
          "s]>li]:whitespace-nowrap [&_[data-part=price-axis]>li]:[transform:translateY(-50%)] [&_[data-part=price-a" +
          "xis]>li:first-child]:[transform:none] [&_[data-part=price-axis]>li:last-child]:[transform:translateY(-100" +
          "%)] [&_[data-part=time-axis]]:relative [&_[data-part=time-axis]]:[inset-block:0] [&_[data-part=time-axis]" +
          "]:[inline-size:var(--candle-content-size,_100%)] [&_[data-part=time-axis]]:[translate:calc(-1_*_var(--can" +
          "dle-scroll-x,_0px))_0] [&_[data-part=time-axis]]:[min-inline-size:0] [&_[data-part=time-axis]>li]:absolut" +
          "e [&_[data-part=time-axis]>li]:[inset-block-start:0.375rem] [&_[data-part=time-axis]>li]:[inset-inline-st" +
          "art:var(--candle-axis-x)] [&_[data-part=time-axis]>li]:[color:var(--candle-axis)] [&_[data-part=time-axis" +
          "]>li]:[font-size:0.7rem] [&_[data-part=time-axis]>li]:whitespace-nowrap [&_[data-part=time-axis]>li]:[tra" +
          "nsform:translateX(-50%)] [&_[data-part=time-axis]>li:first-child]:[transform:none] [&_[data-part=time-axi" +
          "s]>li:last-child]:[transform:translateX(-100%)] [&_[data-part=time-axis]>li:only-child]:[transform:transl" +
          "ateX(-50%)] [&_[data-part=time-axis]>li[data-part=crosshair-time]]:[transform:translateX(-50%)] [&_[data-" +
          "part=price-axis]>li[data-part=crosshair-price]]:[transform:translateY(-50%)] [&>table]:absolute [&>table]" +
          ":[inline-size:1px] [&>table]:[block-size:1px] [&>table]:overflow-hidden [&>table]:[clip-path:inset(50%)] " +
          "[&>table]:whitespace-nowrap"
        }
        data={candles}
        visibleCount={20}
        aria-label="Live BTC / USD candles"
      />
    </>
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('[--candle-grid:color-mix(in_srgb,_currentcolor_10%,_transparent)] [--candle-down:oklch(64%_0.21_24deg)] [--candle-flat:color-mix(in_srgb,_currentcolor_60%,_transparent)] [--candle-up:oklch(67%_0.14_166deg)] [--candle-axis:var(--muted-foreground)] relative block [inline-size:100%] [min-block-size:21rem] [padding:1rem_0.75rem_0.5rem] overflow-clip [overscroll-behavior:none] isolate [color-scheme:light_dark] bg-transparent [color:light-dark(oklch(28%_0.04_165deg),_oklch(82%_0.04_165deg))] data-[interactive]:[touch-action:none] [&[data-interactive]_[data-part=scroll-viewport]]:[overscroll-behavior-inline:none] [&>[data-part=plot]]:relative [&>[data-part=plot]]:grid [&>[data-part=plot]]:[grid-template-columns:minmax(0,_1fr)_4.5rem] [&>[data-part=plot]]:[grid-template-rows:minmax(18rem,_1fr)_calc(1.5rem_+_var(--candle-scrollbar-size,_0px))] [&>[data-part=plot]]:[gap:0_0.75rem] [&>[data-part=plot]]:[min-inline-size:0] [&>[data-part=plot]]:[min-block-size:18rem] [&>[data-part=plot]]:[overscroll-behavior:none] [&_[data-part=scroll-viewport]]:[grid-column:1] [&_[data-part=scroll-viewport]]:[grid-row:1_/_span_2] [&_[data-part=scroll-viewport]]:[min-inline-size:0] [&_[data-part=scroll-viewport]]:[min-block-size:18rem] [&_[data-part=scroll-viewport]]:[overflow:auto_hidden] [&_[data-part=scroll-viewport]]:[container-type:inline-size] [&_[data-part=scroll-viewport]]:[direction:rtl] [&_[data-part=canvas]]:grid [&_[data-part=canvas]]:[grid-template-rows:minmax(18rem,_1fr)_1.5rem] [&_[data-part=canvas]]:[inline-size:calc(100%_*_var(--candle-scale))] [&_[data-part=canvas]]:[min-inline-size:100%] [&_[data-part=canvas]]:[min-block-size:100%] [&_[data-part=canvas]]:[direction:ltr] [&_[data-part=candles]]:absolute [&_[data-part=candles]]:[inset-block:0] [&_[data-part=candles]]:[inset-inline:auto_0] [&_[data-part=candles]]:[inline-size:100%] [&_[data-part=candles]]:m-0 [&_[data-part=candles]]:[padding:1rem_0.5rem] [&_[data-part=candles]]:list-none [&_[data-part=viewport]>[data-uiify-virtual-scroll]]:absolute [&_[data-part=viewport]>[data-uiify-virtual-scroll]]:inset-0 [&_[data-uiify-virtual-scroll]_[data-part=candle]]:[inset-block:1rem_auto] [&_[data-uiify-virtual-scroll]_[data-part=candle]]:[block-size:calc(var(--candle-plot-height,_18rem)_-_2rem)] [&_[data-part=candles]]:[background-image:linear-gradient(to_right,_var(--candle-grid)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle-grid)_1px,_transparent_1px)] [&_[data-part=candles]]:[background-size:10%_100%,_100%_25%] [&_[data-part=viewport]:has(>[data-uiify-virtual-scroll])]:[background-image:linear-gradient(to_right,_var(--candle-grid)_1px,_transparent_1px),_linear-gradient(to_bottom,_var(--candle-grid)_1px,_transparent_1px)] [&_[data-part=viewport]:has(>[data-uiify-virtual-scroll])]:[background-size:10%_100%,_100%_25%] [&_[data-part=viewport]]:relative [&_[data-part=viewport]]:[grid-column:1] [&_[data-part=viewport]]:[grid-row:1] [&_[data-part=viewport]]:[min-inline-size:0] [&_[data-part=viewport]]:[min-block-size:18rem] [&_[data-part=viewport]]:overflow-clip [&_[data-part=viewport]]:[overscroll-behavior:none] [&_[data-part=time-viewport]]:relative [&_[data-part=time-viewport]]:[grid-column:1] [&_[data-part=time-viewport]]:[grid-row:2] [&_[data-part=time-viewport]]:[min-inline-size:0] [&_[data-part=time-viewport]]:overflow-clip [&_[data-part=time-viewport]]:[overscroll-behavior:none] [&>figcaption]:absolute [&>figcaption]:z-[1] [&>figcaption]:[inset-block-start:0.75rem] [&>figcaption]:[inset-inline-start:1rem] [&>figcaption]:text-muted-foreground [&>figcaption]:[font-size:0.75rem] [&>figcaption]:[font-weight:650] [&>figcaption]:[letter-spacing:0.04em] [&>figcaption]:[text-transform:uppercase] [&_[data-part=readout]]:absolute [&_[data-part=readout]]:z-[1] [&_[data-part=readout]]:[inset-block-start:0.75rem] [&_[data-part=readout]]:[inset-inline-end:1rem] [&_[data-part=readout]]:flex [&_[data-part=readout]]:flex-wrap [&_[data-part=readout]]:[gap:0.375rem_0.625rem] [&_[data-part=readout]]:items-baseline [&_[data-part=readout]]:[color:var(--candle-axis)] [&_[data-part=readout]]:[font-size:0.7rem] [&_[data-part=readout]]:[font-variant-numeric:tabular-nums] [&_[data-part=readout]]:leading-none [&_[data-part=readout]]:whitespace-nowrap [&_[data-part=readout-time]]:[font-weight:650] [&_[data-part=candle]]:absolute [&_[data-part=candle]]:[inset:1rem_0.5rem] [&_[data-part=candle]]:pointer-events-none [&_[data-part=candle]]:[inset-inline-start:var(--candle-x)] [&_[data-part=candle]]:[inline-size:var(--candle-slot)] [&_[data-part=candle]]:block [&_[data-part=candle]]:[color:var(--candle-flat)] [&_[data-part=candle]]:list-none [&[data-interactive]_[data-part=candle]]:[pointer-events:auto] [&_[data-part=candle-hit]]:absolute [&_[data-part=candle-hit]]:z-[1] [&_[data-part=candle-hit]]:inset-0 [&_[data-part=candle-hit]]:[inline-size:100%] [&_[data-part=candle-hit]]:[block-size:100%] [&_[data-part=candle-hit]]:m-0 [&_[data-part=candle-hit]]:p-0 [&_[data-part=candle-hit]]:border-0 [&_[data-part=candle-hit]]:border-current [&_[data-part=candle-hit]]:border-none [&_[data-part=candle-hit]]:appearance-none [&_[data-part=candle-hit]]:bg-transparent [&_[data-part=candle-hit]]:text-transparent [&_[data-part=candle-hit]]:[cursor:crosshair] [&_[data-part=candle-hit]]:[font-style:inherit] [&_[data-part=candle-hit]]:[font-variant:inherit] [&_[data-part=candle-hit]]:[font-weight:inherit] [&_[data-part=candle-hit]]:[font-stretch:inherit] [&_[data-part=candle-hit]]:text-[length:inherit] [&_[data-part=candle-hit]]:leading-[inherit] [&_[data-part=candle-hit]]:font-[family-name:inherit] [&_[data-part=candle]::before]:absolute [&_[data-part=candle]::before]:block [&_[data-part=candle]::before]:[background:currentcolor] [&_[data-part=candle]::after]:absolute [&_[data-part=candle]::after]:block [&_[data-part=candle]::after]:[background:currentcolor] [&_[data-part=candle]::before]:[inset-block-start:var(--candle-wick-top)] [&_[data-part=candle]::before]:[inset-inline-start:50%] [&_[data-part=candle]::before]:[inline-size:max(1px,_0.08em)] [&_[data-part=candle]::before]:[block-size:var(--candle-wick-height)] [&_[data-part=candle]::before]:[transform:translateX(-50%)] [&_[data-part=candle]::after]:[inset-block-start:var(--candle-body-top)] [&_[data-part=candle]::after]:[inset-inline:17%] [&_[data-part=candle]::after]:[block-size:var(--candle-body-height)] [&_[data-part=candle]::after]:[min-block-size:1px] [&_[data-part=candle][data-direction=up]]:[color:var(--candle-up)] [&_[data-part=candle][data-direction=down]]:[color:var(--candle-down)] [&_[data-part=crosshair]]:absolute [&_[data-part=crosshair]]:z-[3] [&_[data-part=crosshair]]:inset-0 [&_[data-part=crosshair]]:[inline-size:var(--candle-content-size,_100%)] [&_[data-part=crosshair]]:[translate:calc(-1_*_var(--candle-scroll-x,_0px))_0] [&_[data-part=crosshair]]:[block-size:100%] [&_[data-part=crosshair]]:[color:light-dark(oklch(52%_0.01_0deg),_oklch(72%_0.01_0deg))] [&_[data-part=crosshair]]:pointer-events-none [&_[data-part=crosshair]::before]:absolute [&_[data-part=crosshair]::before]:block [&_[data-part=crosshair]::before]:[background:currentcolor] [&_[data-part=crosshair]::after]:absolute [&_[data-part=crosshair]::after]:block [&_[data-part=crosshair]::after]:[background:currentcolor] [&_[data-part=crosshair]::before]:[inset-block:0] [&_[data-part=crosshair]::before]:[inset-inline-start:var(--candle-crosshair-x)] [&_[data-part=crosshair]::before]:[inline-size:1px] [&_[data-part=crosshair]::before]:[background-image:repeating-linear-gradient(_to_bottom,_currentcolor_0_0.4rem,_transparent_0.4rem_0.8rem_)] [&_[data-part=crosshair]::before]:bg-transparent [&_[data-part=crosshair]::after]:[inset-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair]::after]:[inset-inline:0] [&_[data-part=crosshair]::after]:[block-size:1px] [&_[data-part=crosshair]::after]:[background-image:repeating-linear-gradient(_to_right,_currentcolor_0_0.4rem,_transparent_0.4rem_0.8rem_)] [&_[data-part=crosshair]::after]:bg-transparent [&_[data-part=crosshair-marker]]:absolute [&_[data-part=crosshair-marker]]:[inset-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=crosshair-marker]]:[inset-inline-start:var(--candle-crosshair-x)] [&_[data-part=crosshair-marker]]:[font-size:1rem] [&_[data-part=crosshair-marker]]:leading-none [&_[data-part=crosshair-marker]]:[transform:translate(-50%,_-50%)] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[inset-block-start:0] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[inset-inline-start:var(--candle-crosshair-x)] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[padding:0.25rem_0.5rem] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[background:var(--candle-axis)] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[color:Canvas] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[font-weight:650] [&_[data-part=time-axis]>[data-part=crosshair-time]]:[transform:translateX(-50%)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-block-start:calc(var(--candle-cursor-y,_50%)_+_1rem)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[inset-inline-end:0] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[padding:0.25rem_0.5rem] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[background:var(--candle-axis)] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[color:Canvas] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[font-weight:650] [&_[data-part=price-axis]>[data-part=crosshair-price]]:[transform:translateY(-50%)] [&[data-interactive]_[data-part=candle-hit]:focus-visible]:[outline:2px_solid_currentcolor] [&[data-interactive]_[data-part=candle-hit]:focus-visible]:[outline-offset:-2px] [&_[data-part=price-axis]]:m-0 [&_[data-part=price-axis]]:p-0 [&_[data-part=price-axis]]:list-none [&_[data-part=time-axis]]:m-0 [&_[data-part=time-axis]]:p-0 [&_[data-part=time-axis]]:list-none [&_[data-part=price-axis]]:relative [&_[data-part=price-axis]]:[grid-column:2] [&_[data-part=price-axis]]:[grid-row:1] [&_[data-part=price-axis]]:[min-inline-size:0] [&_[data-part=price-axis]>li]:absolute [&_[data-part=price-axis]>li]:[inset-inline:0] [&_[data-part=price-axis]>li]:[inset-block-start:var(--candle-axis-y)] [&_[data-part=price-axis]>li]:overflow-hidden [&_[data-part=price-axis]>li]:[color:var(--candle-axis)] [&_[data-part=price-axis]>li]:[font-size:0.65rem] [&_[data-part=price-axis]>li]:[font-variant-numeric:tabular-nums] [&_[data-part=price-axis]>li]:leading-none [&_[data-part=price-axis]>li]:text-end [&_[data-part=price-axis]>li]:[text-overflow:ellipsis] [&_[data-part=price-axis]>li]:whitespace-nowrap [&_[data-part=price-axis]>li]:[transform:translateY(-50%)] [&_[data-part=price-axis]>li:first-child]:[transform:none] [&_[data-part=price-axis]>li:last-child]:[transform:translateY(-100%)] [&_[data-part=time-axis]]:relative [&_[data-part=time-axis]]:[inset-block:0] [&_[data-part=time-axis]]:[inline-size:var(--candle-content-size,_100%)] [&_[data-part=time-axis]]:[translate:calc(-1_*_var(--candle-scroll-x,_0px))_0] [&_[data-part=time-axis]]:[min-inline-size:0] [&_[data-part=time-axis]>li]:absolute [&_[data-part=time-axis]>li]:[inset-block-start:0.375rem] [&_[data-part=time-axis]>li]:[inset-inline-start:var(--candle-axis-x)] [&_[data-part=time-axis]>li]:[color:var(--candle-axis)] [&_[data-part=time-axis]>li]:[font-size:0.7rem] [&_[data-part=time-axis]>li]:whitespace-nowrap [&_[data-part=time-axis]>li]:[transform:translateX(-50%)] [&_[data-part=time-axis]>li:first-child]:[transform:none] [&_[data-part=time-axis]>li:last-child]:[transform:translateX(-100%)] [&_[data-part=time-axis]>li:only-child]:[transform:translateX(-50%)] [&_[data-part=time-axis]>li[data-part=crosshair-time]]:[transform:translateX(-50%)] [&_[data-part=price-axis]>li[data-part=crosshair-price]]:[transform:translateY(-50%)] [&>table]:absolute [&>table]:[inline-size:1px] [&>table]:[block-size:1px] [&>table]:overflow-hidden [&>table]:[clip-path:inset(50%)] [&>table]:whitespace-nowrap');

@source inline("[&_[data-part=candle]::before]:content-[''] [&_[data-part=candle]::after]:content-[''] [&_[data-part=crosshair]::before]:content-[''] [&_[data-part=crosshair]::after]:content-['']");

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

CandleChart

PropTipoPredeterminadoDescripción
data*readonly CandleChartData[]—Registros OHLC; cada elemento contiene valores de tiempo, apertura, máximo, mínimo y cierre.
aria-labelstring"Candlestick chart"Nombre accesible del gráfico y su tabla de datos.
xAxisreadonly CandleChartAxisLabel[]—Etiquetas personalizadas opcionales del eje inferior. Cada elemento proporciona contenido de React arbitrario y una posición entre 0 y 100 por ciento.
yAxisreadonly CandleChartAxisLabel[]—Etiquetas personalizadas opcionales del eje derecho. Cada elemento proporciona contenido de React arbitrario y una posición entre 0 y 100 por ciento.
interactiveboolean—Activa las áreas interactivas de las velas, el estado de la cruz guía, la activación con teclado y la lectura OHLC renderizada con React; CandleChartClient lo establece automáticamente.
renderReactElement | ((props, state) => ReactElement)—Reemplaza el elemento renderizado y conserva las conexiones de comportamiento y accesibilidad.

CandleChartClient (@gunkin/uiify/components/candle-chart/client)

PropTipoPredeterminadoDescripción
data*readonly CandleChartData[]—Los mismos datos OHLC que CandleChart; el cliente añade zoom con la rueda, desplazamiento horizontal, una cruz guía ajustada a las velas, selección de velas con teclado, valores de eje fijos y una lectura OHLC.
visibleCountnumber—Modo en vivo: N velas llenan el área visible; el historial se virtualiza. Los ejes, la lectura y la tabla siguen las velas visibles; el gráfico sigue las nuevas salvo que se retroceda con el desplazamiento, con el zoom y los anuncios desactivados.

useChartViewport (@gunkin/uiify/hooks)

PropTipoPredeterminadoDescripción
itemCount*number—Número de velas en el modelo del área visible.
initialScalenumber3.2Escala CSS inicial; el área visible comienza fijada al borde derecho.
minScale / maxScalenumber—Límites de zoom opcionales. El zoom nunca reduce el gráfico por debajo del tamaño del contenedor; el máximo predeterminado es la mitad del número de elementos, por lo que 100 elementos limitan cada espacio de vela al 50%.

Teclado

TeclaAcción
TabDar el foco a una vela interactiva
Enter / SpaceSeleccionar la vela con foco y actualizar la lectura

Accesibilidad

Los glifos estáticos de velas son decorativos y la figura incluye una tabla oculta visualmente con los valores originales de tiempo, apertura, máximo, mínimo y cierre. La entrada de cliente opcional permite dar el foco a las velas con teclado, añade zoom con la rueda, desplazamiento horizontal nativo, una cruz guía ajustada y una lectura OHLC renderizada con React, conservando la tabla.

Puntos de estilo

data-uiify-candle-chartdata-interactivedata-directiondata-timedata-crosshair-activedata-axis--candle-x--candle-slot--candle-wick-top--candle-wick-height--candle-body-top--candle-body-height--candle-axis-x--candle-axis-y--candle-scale--candle-crosshair-x--candle-cursor-y