Moodinary/UI

Collapsible

Esconder detalle opcional (“cómo calculamos esto”).

Muestra u oculta un detalle secundario.

Instalación

shadcn
npx shadcn@latest add https://design.moodinary.com/r/collapsible.json
import
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@moodinary/ui/components/collapsible";

Ejemplos

Fila de card

Así se usa en Facturación: variant="row" en trigger y contenido, dentro de una Card sin padding. Plegado por defecto.

Código
plan-comparison.tsx
import { Card } from "@moodinary/ui/components/card";
import {
	Collapsible,
	CollapsibleContent,
	CollapsibleTrigger,
} from "@moodinary/ui/components/collapsible";
import { CheckIcon } from "@moodinary/ui/components/icons";

const plans = ["Basic", "Core", "Insight", "Horizon"];
const features: [string, number][] = [
	["Exportar pulsos a CSV", 0],
	["Moderación con IA", 1],
	["Alertas inteligentes", 1],
	["Calendario organizacional", 2],
	["API de lectura", 3],
];

export default function CollapsiblePlanComparison() {
	return (
		<Card className="w-full p-0">
			<Collapsible>
				<CollapsibleTrigger variant="row">
					Comparar todos los planes
				</CollapsibleTrigger>
				<CollapsibleContent variant="row">
					<table className="w-full text-xs">
						<thead>
							<tr className="text-left text-ink-3">
								<th className="px-5 py-2 font-normal">Función</th>
								{plans.map((plan) => (
									<th className="px-3 py-2 text-center font-medium" key={plan}>
										{plan}
									</th>
								))}
							</tr>
						</thead>
						<tbody>
							{features.map(([label, from]) => (
								<tr className="border-line border-t" key={label}>
									<td className="px-5 py-2 text-ink-2">{label}</td>
									{plans.map((plan, index) => (
										<td className="px-3 py-2 text-center" key={plan}>
											{index >= from ? (
												<CheckIcon
													aria-label="Incluido"
													className="mx-auto size-3.5"
												/>
											) : (
												<span className="text-ink-3">
													<span aria-hidden>–</span>
													<span className="sr-only">No incluido</span>
												</span>
											)}
										</td>
									))}
								</tr>
							))}
						</tbody>
					</table>
				</CollapsibleContent>
			</Collapsible>
		</Card>
	);
}

Detalle

Cerrado por defecto, para explicaciones opcionales.

Código
detail.tsx
import {
	Collapsible,
	CollapsibleContent,
	CollapsibleTrigger,
} from "@moodinary/ui/components/collapsible";

export default function CollapsibleDetail() {
	return (
		<Collapsible>
			<CollapsibleTrigger>Cómo leer este gráfico</CollapsibleTrigger>
			<CollapsibleContent>
				Cada respuesta va de 1 a 5. El clima sale del promedio: desde 4,2 es
				soleado, desde 3,5 parcial, desde 2,8 nublado y por debajo, tormenta.
				Con menos de 8 pulsos en la semana aparece niebla. Los valores de los
				gráficos de esta página son ilustrativos.
			</CollapsibleContent>
		</Collapsible>
	);
}

Estados

Abierto con defaultOpen y deshabilitado.

Este panel arranca abierto y se puede cerrar.
Código
states.tsx
import {
	Collapsible,
	CollapsibleContent,
	CollapsibleTrigger,
} from "@moodinary/ui/components/collapsible";

export default function CollapsibleStates() {
	return (
		<div className="grid w-full gap-4">
			<Collapsible defaultOpen>
				<CollapsibleTrigger>Detalle abierto</CollapsibleTrigger>
				<CollapsibleContent>
					Este panel arranca abierto y se puede cerrar.
				</CollapsibleContent>
			</Collapsible>
			<Collapsible disabled>
				<CollapsibleTrigger>Detalle no disponible</CollapsibleTrigger>
				<CollapsibleContent>El control está deshabilitado.</CollapsibleContent>
			</Collapsible>
		</div>
	);
}

Props

Collapsible

PropTipoDefaultDescripción
defaultOpenbooleanfalseAbierto al inicio.
openboolean-Controlado.
onOpenChange(open: boolean) => void-Se llama al cambiar.
disabledbooleanfalseBloquea el control.
classNamestring-Clases extra.

CollapsibleTrigger, CollapsibleContent

PropTipoDefaultDescripción
variant"inline" | "row""inline"inline: link chico con chevron a la izquierda. row: fila de card a todo el ancho, chevron a la derecha.
childrenReactNode-Disparador y contenido.
classNamestring-Clases extra.

Cuándo sí y cuándo no

Hacé
  • Usalo para detalles opcionales.
  • Escribí el disparador como lo que muestra.
  • Mantené el contenido breve.
Evitá
  • No escondas errores ni avisos.
  • No lo uses para navegación.
  • No pongas formularios largos adentro.

Accesibilidad

  • El disparador es un botón con aria-expanded.
  • Enter y Espacio lo abren y cierran.