Saltar al contenido principal

Frame

Un contenedor estructurado que anida paneles, como una card dentro de una card.

Workspace

Plan and usage for the acme team.

Pro planActive

Monthly usage

4,210 of 10,000 requests

1import { Badge } from '@/components/ui/badge';
2import { Button } from '@/components/ui/button';
3import { Card } from '@/components/ui/card';
4import { Frame } from '@/components/ui/frame';
5
6export function Default() {
7 return (
8 <Frame className="max-w-md">
9 <Frame.Header>
10 <Frame.Title>Workspace</Frame.Title>
11 <Frame.Description>Plan and usage for the acme team.</Frame.Description>
12 </Frame.Header>
13 <Frame.Panel>
14 <div className="flex flex-col gap-3">
15 <div className="flex items-center justify-between">
16 <span className="text-sm font-medium">Pro plan</span>
17 <Badge variant="success">Active</Badge>
18 </div>
19 <Card variant="outline">
20 <Card.Header compact>
21 <Card.Title>Monthly usage</Card.Title>
22 <Card.Description>4,210 of 10,000 requests</Card.Description>
23 </Card.Header>
24 <Card.Content compact>
25 <div className="bg-muted h-1.5 w-full overflow-hidden rounded-full">
26 <div className="bg-primary h-full w-2/5 rounded-full" />
27 </div>
28 </Card.Content>
29 </Card>
30 </div>
31 </Frame.Panel>
32 <Frame.Footer className="justify-end">
33 <Button size="sm" variant="ghost">
34 Invoices
35 </Button>
36 <Button size="sm" variant="outline">
37 Manage plan
38 </Button>
39 </Frame.Footer>
40 </Frame>
41 );
42}

Instalación

pnpm dlx nachui add frame

Anatomía

1import { Frame } from '@/components/ui/frame';
1<Frame>
2 <Frame.Header>
3 <Frame.Title>Workspace</Frame.Title>
4 <Frame.Description>Plan y uso del equipo acme.</Frame.Description>
5 </Frame.Header>
6 <Frame.Panel>Contenido del panel</Frame.Panel>
7 <Frame.Footer>Acciones</Frame.Footer>
8</Frame>
El frame es una superficie muted y cada panel es una card apoyada sobre ella, con un radio menor para que las esquinas queden concéntricas. Los paneles aceptan cualquier contenido, incluida una Card u otro Frame, y así se logra el efecto de card dentro de card.

Composición

Usa la siguiente composición para construir un Frame:
Frame
├── Frame.Header
│ ├── Frame.Title
│ └── Frame.Description
├── Frame.Panel
└── Frame.Footer

Variantes

Apilado

stacked elimina los espacios y conecta los paneles consecutivos en un solo bloque con bordes compartidos. Agrega dense para quitar el padding del panel y controlarlo desde tu propio contenido, útil para filas de lista.

Services

Status across regions, updated every minute.

auth-serviceus-east-1
Healthy
registry-apius-east-1
Healthy
rag-workereu-west-2
Degraded
ingest-croneu-west-2
Stopped
1import { Badge } from '@/components/ui/badge';
2import { Frame } from '@/components/ui/frame';
3
4const SERVICES = [
5 { name: 'auth-service', region: 'us-east-1', status: 'Healthy', variant: 'success' },
6 { name: 'registry-api', region: 'us-east-1', status: 'Healthy', variant: 'success' },
7 { name: 'rag-worker', region: 'eu-west-2', status: 'Degraded', variant: 'warning' },
8 { name: 'ingest-cron', region: 'eu-west-2', status: 'Stopped', variant: 'destructive' },
9] as const;
10
11export function Stacked() {
12 return (
13 <Frame stacked dense className="max-w-md">
14 <Frame.Header>
15 <Frame.Title>Services</Frame.Title>
16 <Frame.Description>Status across regions, updated every minute.</Frame.Description>
17 </Frame.Header>
18 {SERVICES.map((service) => (
19 <Frame.Panel key={service.name}>
20 <div className="flex items-center justify-between gap-3 px-4 py-3">
21 <div className="flex min-w-0 flex-col">
22 <span className="truncate font-mono text-sm">{service.name}</span>
23 <span className="text-muted-foreground text-xs">{service.region}</span>
24 </div>
25 <Badge variant={service.variant}>{service.status}</Badge>
26 </div>
27 </Frame.Panel>
28 ))}
29 </Frame>
30 );
31}

Referencia de API

Frame

PropTypeDefaultDescription
variant'default' | 'ghost''default'ghost quita el borde exterior y el fondo
spacing'sm' | 'default' | 'lg''default'Padding del frame y separación entre paneles
stackedbooleanfalseConecta paneles consecutivos con bordes compartidos
densebooleanfalseQuita el padding por defecto del panel
classNamestring-Clases CSS adicionales

Frame.Title

PropTypeDefaultDescription
as'h2' | 'h3' | 'h4' | 'h5' | 'h6''h3'Nivel de encabezado
classNamestring-Clases CSS adicionales

Frame.Header, Frame.Description, Frame.Panel, Frame.Footer

Partes de layout del frame. Cada una acepta className y las props estándar de div.
¿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