Saltar al contenido principal

Scroll Area

Una región con scroll y una barra propia, acorde al tema, que aparece al pasar el cursor o al desplazarse.

Releases

  • v2.24.0Security fixes
  • v2.23.0Improvements
  • v2.22.0Improvements
  • v2.21.0Security fixes
  • v2.20.0Improvements
  • v2.19.0Improvements
  • v2.18.0Security fixes
  • v2.17.0Improvements
  • v2.16.0Improvements
  • v2.15.0Security fixes
  • v2.14.0Improvements
  • v2.13.0Improvements
  • v2.12.0Security fixes
  • v2.11.0Improvements
  • v2.10.0Improvements
  • v2.9.0Security fixes
  • v2.8.0Improvements
  • v2.7.0Improvements
  • v2.6.0Security fixes
  • v2.5.0Improvements
  • v2.4.0Improvements
  • v2.3.0Security fixes
  • v2.2.0Improvements
  • v2.1.0Improvements
1import { ScrollArea } from '@/components/ui/scroll-area';
2
3const versions = Array.from({ length: 24 }, (_, index) => {
4 const minor = 24 - index;
5 return { tag: `v2.${minor}.0`, note: minor % 3 === 0 ? 'Security fixes' : 'Improvements' };
6});
7
8export function Default() {
9 return (
10 <ScrollArea className="border-border bg-card h-72 w-56 rounded-lg border">
11 <div className="p-3">
12 <p className="text-muted-foreground mb-3 px-1 text-xs font-medium tracking-wide uppercase">
13 Releases
14 </p>
15 <ul className="flex flex-col">
16 {versions.map((version) => (
17 <li
18 key={version.tag}
19 className="border-border flex items-center justify-between border-b px-1 py-2 text-sm last:border-0"
20 >
21 <span className="font-medium">{version.tag}</span>
22 <span className="text-muted-foreground text-xs">{version.note}</span>
23 </li>
24 ))}
25 </ul>
26 </div>
27 </ScrollArea>
28 );
29}

Instalación

pnpm dlx nachui add scroll-area

Anatomía

1import { ScrollArea } from '@/components/ui/scroll-area';
1<ScrollArea className="h-72 w-56 rounded-md border">
2 <div className="p-4">Contenido largo</div>
3</ScrollArea>
La raíz envuelve tu contenido en un viewport que hace scroll nativo con la barra del navegador oculta, y dibuja su propio pulgar encima. Rueda, touch, teclado y arrastre siguen funcionando porque el viewport es un elemento normal con overflow. El pulgar se arrastra con el puntero y la pista salta al hacer click.

Composición

ScrollArea
└── ScrollArea.Bar
La raíz renderiza una Bar por cada dirección de orientation. Agrega una Bar propia con forceMount cuando necesites una que nunca se oculte.

Variantes

Predeterminado (Default)

Scroll vertical. Con type="hover" (el valor por defecto) la barra aparece mientras el puntero está sobre el área o el contenido se desplaza.

Releases

  • v2.24.0Security fixes
  • v2.23.0Improvements
  • v2.22.0Improvements
  • v2.21.0Security fixes
  • v2.20.0Improvements
  • v2.19.0Improvements
  • v2.18.0Security fixes
  • v2.17.0Improvements
  • v2.16.0Improvements
  • v2.15.0Security fixes
  • v2.14.0Improvements
  • v2.13.0Improvements
  • v2.12.0Security fixes
  • v2.11.0Improvements
  • v2.10.0Improvements
  • v2.9.0Security fixes
  • v2.8.0Improvements
  • v2.7.0Improvements
  • v2.6.0Security fixes
  • v2.5.0Improvements
  • v2.4.0Improvements
  • v2.3.0Security fixes
  • v2.2.0Improvements
  • v2.1.0Improvements
1import { ScrollArea } from '@/components/ui/scroll-area';
2
3const versions = Array.from({ length: 24 }, (_, index) => {
4 const minor = 24 - index;
5 return { tag: `v2.${minor}.0`, note: minor % 3 === 0 ? 'Security fixes' : 'Improvements' };
6});
7
8export function Default() {
9 return (
10 <ScrollArea className="border-border bg-card h-72 w-56 rounded-lg border">
11 <div className="p-3">
12 <p className="text-muted-foreground mb-3 px-1 text-xs font-medium tracking-wide uppercase">
13 Releases
14 </p>
15 <ul className="flex flex-col">
16 {versions.map((version) => (
17 <li
18 key={version.tag}
19 className="border-border flex items-center justify-between border-b px-1 py-2 text-sm last:border-0"
20 >
21 <span className="font-medium">{version.tag}</span>
22 <span className="text-muted-foreground text-xs">{version.note}</span>
23 </li>
24 ))}
25 </ul>
26 </div>
27 </ScrollArea>
28 );
29}

Horizontal

orientation="horizontal" oculta el overflow vertical y dibuja la barra en el borde inferior.
Virginiaus-east-112 ms
Oregonus-west-248 ms
Frankfurteu-central-196 ms
Sao Paulosa-east-1140 ms
Singaporeap-southeast-1210 ms
Sydneyap-southeast-2245 ms
Tokyoap-northeast-1180 ms
1import { ScrollArea } from '@/components/ui/scroll-area';
2
3const regions = [
4 { city: 'Virginia', code: 'us-east-1', latency: '12 ms' },
5 { city: 'Oregon', code: 'us-west-2', latency: '48 ms' },
6 { city: 'Frankfurt', code: 'eu-central-1', latency: '96 ms' },
7 { city: 'Sao Paulo', code: 'sa-east-1', latency: '140 ms' },
8 { city: 'Singapore', code: 'ap-southeast-1', latency: '210 ms' },
9 { city: 'Sydney', code: 'ap-southeast-2', latency: '245 ms' },
10 { city: 'Tokyo', code: 'ap-northeast-1', latency: '180 ms' },
11];
12
13export function Horizontal() {
14 return (
15 <ScrollArea orientation="horizontal" className="w-full max-w-md">
16 <div className="flex gap-3 p-1 pb-3">
17 {regions.map((region) => (
18 <div
19 key={region.code}
20 className="border-border bg-card flex w-36 shrink-0 flex-col gap-1 rounded-lg border p-3"
21 >
22 <span className="text-sm font-medium">{region.city}</span>
23 <span className="text-muted-foreground font-mono text-xs">{region.code}</span>
24 <span className="text-muted-foreground text-xs">{region.latency}</span>
25 </div>
26 ))}
27 </div>
28 </ScrollArea>
29 );
30}

Ambas direcciones

orientation="both" para tablas anchas. type="always" mantiene las barras visibles siempre que el contenido desborde.
RouteMethodp50p95p99ErrorsRequestsRegion
/api/ordersGET32 ms120 ms340 ms0.1%1.2Mus-east-1
/api/ordersPOST58 ms210 ms610 ms0.4%240Kus-east-1
/api/customersGET21 ms88 ms190 ms0.0%980Keu-central-1
/api/invoicesGET44 ms160 ms420 ms0.2%410Keu-central-1
/api/invoices/:id/pdfGET310 ms900 ms1.8 s1.1%32Kus-west-2
/api/webhooksPOST12 ms40 ms95 ms0.0%3.4Map-southeast-1
/api/searchGET80 ms260 ms700 ms0.3%620Kus-east-1
/api/exportsPOST1.2 s3.4 s6.1 s2.0%8Ksa-east-1
/api/auth/sessionGET9 ms30 ms70 ms0.0%5.1Mus-east-1
/api/auth/loginPOST140 ms400 ms900 ms0.8%150Kus-east-1
1import { ScrollArea } from '@/components/ui/scroll-area';
2
3const columns = ['Route', 'Method', 'p50', 'p95', 'p99', 'Errors', 'Requests', 'Region'];
4
5const rows = [
6 ['/api/orders', 'GET', '32 ms', '120 ms', '340 ms', '0.1%', '1.2M', 'us-east-1'],
7 ['/api/orders', 'POST', '58 ms', '210 ms', '610 ms', '0.4%', '240K', 'us-east-1'],
8 ['/api/customers', 'GET', '21 ms', '88 ms', '190 ms', '0.0%', '980K', 'eu-central-1'],
9 ['/api/invoices', 'GET', '44 ms', '160 ms', '420 ms', '0.2%', '410K', 'eu-central-1'],
10 ['/api/invoices/:id/pdf', 'GET', '310 ms', '900 ms', '1.8 s', '1.1%', '32K', 'us-west-2'],
11 ['/api/webhooks', 'POST', '12 ms', '40 ms', '95 ms', '0.0%', '3.4M', 'ap-southeast-1'],
12 ['/api/search', 'GET', '80 ms', '260 ms', '700 ms', '0.3%', '620K', 'us-east-1'],
13 ['/api/exports', 'POST', '1.2 s', '3.4 s', '6.1 s', '2.0%', '8K', 'sa-east-1'],
14 ['/api/auth/session', 'GET', '9 ms', '30 ms', '70 ms', '0.0%', '5.1M', 'us-east-1'],
15 ['/api/auth/login', 'POST', '140 ms', '400 ms', '900 ms', '0.8%', '150K', 'us-east-1'],
16];
17
18export function Both() {
19 return (
20 <ScrollArea
21 orientation="both"
22 type="always"
23 className="border-border bg-card h-56 w-full max-w-md rounded-lg border"
24 >
25 <table className="w-max min-w-full text-left text-sm">
26 <thead className="bg-muted/60 text-muted-foreground sticky top-0 text-xs">
27 <tr>
28 {columns.map((column) => (
29 <th key={column} className="px-3 py-2 font-medium whitespace-nowrap">
30 {column}
31 </th>
32 ))}
33 </tr>
34 </thead>
35 <tbody>
36 {rows.map((row) => (
37 <tr key={`${row[0]}-${row[1]}`} className="border-border border-t">
38 {row.map((cell, index) => (
39 <td
40 key={columns[index]}
41 className={
42 index === 0
43 ? 'px-3 py-2 font-mono whitespace-nowrap'
44 : 'px-3 py-2 whitespace-nowrap'
45 }
46 >
47 {cell}
48 </td>
49 ))}
50 </tr>
51 ))}
52 </tbody>
53 </table>
54 </ScrollArea>
55 );
56}

Referencia de API

ScrollArea

PropTipoPor defectoDescripción
orientation"vertical" | "horizontal" | "both""vertical"Qué direcciones hacen scroll
type"auto" | "always" | "hover" | "scroll""hover"Cuándo se ve la barra. Todas requieren overflow
scrollHideDelaynumber600Milisegundos antes de ocultar la barra tras el scroll
viewportRefReact.Ref<HTMLDivElement>-Ref al elemento que hace scroll, para scrollTo y similares
viewportClassNamestring-Clases para el viewport
classNamestring-Clases para la raíz. Dale una altura o un ancho

ScrollArea.Bar

PropTipoPor defectoDescripción
orientation"vertical" | "horizontal""vertical"Qué eje controla la barra
forceMountbooleanfalseMantenerla visible sin importar type
classNamestring-Clases CSS adicionales
¿Encontraste algo que mejorar?

¿Notaste un error, tipografía o detalle faltante en esta página? Ayúdanos a mejorar la documentación abriendo un issue en GitHub.

Crear un Issue
Ctrl+I