Componentes compuestos
Aprende el patrón de componentes compuestos para crear APIs de UI flexibles, tipadas y con estados compartidos.
Los componentes compuestos exponen un único componente raíz junto con subcomponentes con nombre. Este patrón es ideal cuando un elemento de UI tiene varias piezas interactivas que deben permanecer coordinadas, como pestañas, menús o campos de formulario.
En NachUI, los creamos definiendo un componente raíz y luego adjuntando subcomponentes con nombre mediante
Object.assign:1const Tabs = Object.assign(TabsRoot, {2 List: TabsList,3 Trigger: TabsTrigger,4 Content: TabsContent,5});67export { Tabs };
Este patrón se usa en todo el paquete para mantener la API pública simple y consistente, con
<Tabs.List />, <Tabs.Trigger />, y <Tabs.Content />.Por qué usar componentes compuestos
Los componentes compuestos hacen que tu API sea:
- explícita: cada ranura es un subcomponente nombrado en lugar de un
childrengenérico - componible: los usuarios pueden mezclar partes dentro del componente raíz
- tipada: TypeScript puede inferir props específicas para cada subcomponente
- con estado: el componente raíz comparte estado mediante contexto en vez de pasar props manualmente
Cómo funciona
El componente raíz posee la lógica y provee el contexto. Los subcomponentes leen ese contexto para renderizar el comportamiento correcto.
1function Tabs({ children, defaultValue }: TabsProps) {2 const [value, setValue] = useState(defaultValue);34 return (5 <TabsContext.Provider value={{ value, setValue }}>6 <div className="space-y-4">{children}</div>7 </TabsContext.Provider>8 );9}1011Tabs.List = function TabsList({ children }: { children: ReactNode }) {12 return <div className="flex gap-2">{children}</div>;13};1415Tabs.Trigger = function TabsTrigger({ value, children }: TabsTriggerProps) {16 const context = useTabsContext();17 const selected = context.value === value;1819 return (20 <button21 type="button"22 className={cn('rounded-md px-3 py-2', selected ? 'bg-primary text-white' : 'bg-muted')}23 onClick={() => context.setValue(value)}24 >25 {children}26 </button>27 );28};2930Tabs.Content = function TabsContent({ value, children }: TabsContentProps) {31 const context = useTabsContext();32 return context.value === value ? <div>{children}</div> : null;33};
Ejemplo de uso
1<Tabs defaultValue="overview">2 <Tabs.List>3 <Tabs.Trigger value="overview">Resumen</Tabs.Trigger>4 <Tabs.Trigger value="details">Detalles</Tabs.Trigger>5 </Tabs.List>67 <Tabs.Content value="overview">Contenido del resumen</Tabs.Content>8 <Tabs.Content value="details">Contenido de detalles</Tabs.Content>9</Tabs>
Cuándo usar este patrón
Usa componentes compuestos cuando un elemento de UI tiene varias piezas nombradas que dependen de un estado compartido. Buenos candidatos son:
- pestañas
- acordeones
- menús desplegables
- encabezados/pies de diálogo
- controles de formulario con etiqueta y descripción
Si el componente es simple y solo necesita un elemento, prefiere una API de componente único.
Buenas prácticas
- exporta los subcomponentes como miembros estáticos del componente raíz
- mantiene el estado compartido y la generación de clases en el componente raíz
- evita contextos profundamente anidados salvo que la jerarquía lo requiera
- documenta los nombres de los subcomponentes y el orden esperado
- usa props claras y tipadas para cada hijo
Por qué esta arquitectura funciona en NachUI
NachUI prioriza primitivas de UI predecibles y componibles. Los componentes compuestos mantienen las APIs claras y facilitan agregar ranuras opcionales o variantes sin romper a los consumidores.
¿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.