componente · @solu30/ui-kit/navigation
Tabs
Pestañas a partir de una lista de ítems, en tres variantes visuales y con indicador animado.
52 sitios de import en 7 de 15 verticales — un archivo que la importa cuenta una vez, monte una instancia o veinte.
- TheCharterPanel
- carlosmartinpavon
- cmp-packages
- dietaly
- gestorsalon
- luigi
- raquetea
El componente, montado
Cargando el espécimen…
Éste es el conjunto completo. Abajo, los mismos casos por separado, cada uno con su código.
Cómo se usa
import { Tabs } from '@solu30/ui-kit/navigation'<Tabs
items={[
{ key: "reservas", label: "Reservas" },
{ key: "salones", label: "Salones" },
]}
active={solapa}
onChange={setSolapa}
/>Props
| Prop | Requerida | Tipo | Qué hace |
|---|---|---|---|
| items | sí | TabItem$1[] | — |
| active | sí | string | — |
| onChange | sí | (key: string) => void | — |
| size | opcional | "sm" | "md" | — |
| variant | opcional | "underline" | "pills" | "elevated" | — |
| divider | opcional | boolean | Full-width baseline under the tab list (underline variant only). `false` removes the track — the animated per-tab indicator stays. Default `true` (unchanged look for existing consumers). |
| className | opcional | string | — |
Variantes
Cuando alcanza con un array de ítems y un estado activo — la forma más directa de armar pestañas, sin componer el árbol a mano.
Cargando el espécimen…
export function TabsVariantes() {
const [active, setActive] = useState('datos')
return (
<div className="flex w-full flex-col gap-4">
<div className="flex flex-col gap-1.5">
<span className="text-[10px] uppercase tracking-wide text-content/50">
underline · sm — la tira móvil de la pantalla «Empresa» de Dietaly
</span>
<Tabs items={TABS_ITEMS} active={active} onChange={setActive} variant="underline" size="sm" />
</div>
<div className="flex flex-col gap-1.5">
<span className="text-[10px] uppercase tracking-wide text-content/50">pills · sm</span>
<Tabs items={TABS_ITEMS} active={active} onChange={setActive} variant="pills" size="sm" />
</div>
</div>
)
}De specimens/navigation.tsx · TabsVariantes: el espécimen del Muestrario, no un ejemplo oficial del paquete. Muestra cómo se usa la pieza de verdad, montada contra los tipos instalados —eso es lo que vale— pero no es documentación del kit.
Composición
Cuando cada contenido de pestaña necesita más control sobre su propio render — la API estilo Radix, un segundo sistema de tabs del kit con vocabulario distinto al del componente plano.
Cargando el espécimen…
export function TabsCompuesto() {
const [tab, setTab] = useState('ranking')
return (
<div className="mx-auto flex w-full max-w-6xl flex-col gap-5">
<SectionHeader
as="h1"
title="Competir"
description="Tu ranking, tus torneos y tu vitrina."
/>
<TabsRoot value={tab} onValueChange={setTab}>
<TabsList>
<TabsTrigger value="ranking">Ranking</TabsTrigger>
<TabsTrigger value="torneos">Torneos</TabsTrigger>
<TabsTrigger value="trivia" className="inline-flex items-center gap-1.5">
Trivia
<span
aria-hidden="true"
title="Tenés una trivia sin responder"
className="inline-block h-1.5 w-1.5 rounded-full bg-primary"
/>
</TabsTrigger>
</TabsList>
<TabsContent value="ranking" className="pt-4">
<ol className="flex flex-col gap-1.5 text-sm">
<li className="flex items-center justify-between rounded-md bg-inner px-3 py-2">
<span>1 · Sofía Ledesma</span>
<Badge color="success">1.284 pts</Badge>
</li>
<li className="flex items-center justify-between rounded-md bg-inner px-3 py-2">
<span>2 · Nicolás Ávalos</span>
<Badge>1.190 pts</Badge>
</li>
<li className="flex items-center justify-between rounded-md bg-inner px-3 py-2">
<span>3 · Vos</span>
<Badge color="warning">1.147 pts</Badge>
</li>
</ol>
</TabsContent>
<TabsContent value="torneos" className="pt-4">
<p className="text-sm text-content/70">
Torneo relámpago de dobles, sábado 20:00. Quedan 3 lugares.
</p>
</TabsContent>
<TabsContent value="trivia" className="pt-4">
<p className="text-sm text-content/70">
Tenés una trivia sin responder — el punto del trigger es marcado del consumidor,
no una prop del kit.
</p>
</TabsContent>
</TabsRoot>
</div>
)
}De specimens/navigation.tsx · TabsCompuesto: el espécimen del Muestrario, no un ejemplo oficial del paquete. Muestra cómo se usa la pieza de verdad, montada contra los tipos instalados —eso es lo que vale— pero no es documentación del kit.
Ejemplo del paquete
// La versión por DATOS, sin composición: una lista y el activo controlado desde afuera.
const [activo, setActivo] = useState('datos')
<Tabs
items={[{ key: 'datos', label: 'Datos' }, { key: 'pagos', label: 'Pagos', count: 3 }]}
active={activo}
onChange={setActivo}
/>Del @example del JSDoc de @solu30/ui-kit, sin editar: son 65 de los 541 símbolos. La sangría y los renglones en blanco son los del paquete.