Ir al contenido
Contenido y datos

Collapsible

Mostrar y ocultar un bloque con un botón, con el disclosure de iCloud opcional. La pieza simple detrás del Accordion.

import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "sebs7n-ui/collapsible"

Ejemplos

El detalle de una fila

`chevron` suma el disclosure de iCloud: un › que gira a ⌄ al abrir. Sin él, el trigger no trae estilo y va `render={<Button … />}`.

import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "sebs7n-ui/collapsible"

function Basico() {
  return (
    <Collapsible className="w-full max-w-sm gap-1">
      <CollapsibleTrigger chevron className="h-8 px-1 text-callout text-label">
        Factura 0012 · $ 128.400
      </CollapsibleTrigger>
      <CollapsibleContent className="flex flex-col gap-1 rounded-control bg-fill-1 p-3">
        <span>Consultoría — 40 h — $ 96.000</span>
        <span>Hosting — 1 mes — $ 18.400</span>
        <span>Soporte — 1 mes — $ 14.000</span>
      </CollapsibleContent>
    </Collapsible>
  )
}

Filtros avanzados, controlado por la app

Con `open` en el estado, la app sabe si están abiertos: por ejemplo para dejarlos abiertos cuando hay un filtro aplicado.

import { Button } from "sebs7n-ui/button"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "sebs7n-ui/collapsible"
import { DatePicker } from "sebs7n-ui/date-picker"
import { Input } from "sebs7n-ui/input"
import { Label } from "sebs7n-ui/label"
import { useId, useState } from "react"

function Controlado() {
  const [abierto, setAbierto] = useState(false)
  const desde = useId()
  const hasta = useId()
  return (
    <div className="flex w-full max-w-sm flex-col gap-3">
      <Input placeholder="Buscar factura" />
      <Collapsible className="gap-2" onOpenChange={setAbierto} open={abierto}>
        <CollapsibleTrigger render={<Button className="self-start" size="sm" variant="ghost" />}>
          {abierto ? "Ocultar filtros avanzados" : "Filtros avanzados"}
        </CollapsibleTrigger>
        <CollapsibleContent className="flex flex-col gap-3 pt-1">
          <div className="flex flex-col gap-1.5">
            <Label htmlFor={desde}>Desde</Label>
            <DatePicker id={desde} />
          </div>
          <div className="flex flex-col gap-1.5">
            <Label htmlFor={hasta}>Hasta</Label>
            <DatePicker id={hasta} />
          </div>
        </CollapsibleContent>
      </Collapsible>
    </div>
  )
}

Contenido que tiene que existir cerrado

`keepMounted` lo deja en el DOM, oculto: sirve cuando un crawler o el ⌘F del navegador tienen que verlo. Sin él, el contenido cerrado no existe.

import { Button } from "sebs7n-ui/button"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "sebs7n-ui/collapsible"

function KeepMounted() {
  return (
    <Collapsible className="w-full max-w-sm gap-1">
      <CollapsibleTrigger render={<Button size="sm" variant="secondary" />}>Ver claves de recuperación</CollapsibleTrigger>
      <CollapsibleContent className="flex flex-col gap-1 text-mono-callout" keepMounted>
        <span>alien-bean-pasta</span>
        <span>wild-irish-burrito</span>
        <span>horse-battery-staple</span>
      </CollapsibleContent>
    </Collapsible>
  )
}

Props

Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».

Collapsible

Hereda las props de Collapsible.Root.

PropTipoPor defectoDescripción
classNamestring—Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana.
defaultOpenboolean—Heredada de Base UI. Si arranca abierto. Es la versión no controlada de open.
disabledboolean—Heredada de Base UI. Apaga la interacción y lo marca con data-disabled, que es el atributo del que cuelgan los estilos de apagado.
onOpenChange((open: boolean, eventDetails: CollapsibleRootChangeEventDetails) => void)—Heredada de Base UI. Se llama con el estado nuevo cada vez que se abre o se cierra.
openboolean—Heredada de Base UI. Si está abierto. Pasarla lo vuelve controlado: sin onOpenChange ya no se cierra solo.

CollapsibleContent

Hereda las props de Collapsible.Panel.

PropTipoPor defectoDescripción
panelClassNamestring—Clases del panel que anima el alto. El className viaja al contenido, no acá.
classNamestring—Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana.
keepMountedboolean—Heredada de Base UI. Deja el contenido en el DOM mientras está cerrado, en vez de desmontarlo. Cuesta peso; sirve para que un crawler lo vea.

CollapsibleTrigger

Hereda las props de Collapsible.Trigger.

PropTipoPor defectoDescripción
chevronbooleanfalseSuma el chevron › después del texto, que gira a ⌄ al abrir (sin recorrido con movimiento reducido).
classNamestring | ((state: State) => string)—Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana.

Teclado

Enter · Espacio
Abre y cierra.
Tab
Entra y sale del trigger.

Accesibilidad

  • El trigger lleva aria-expanded y aria-controls, puestos por Base UI.
  • El contenido cerrado no está en el DOM salvo keepMounted; con hiddenUntilFound queda y lo encuentra el buscador del navegador.
  • El alto pasa por motion-reduce, además del reset global del paquete.

Reglas de uso

  • Con chevron, el disparador trae el estilo del paquete: 24 de alto mínimo (44 de área con el dedo), foco y el chevron que gira como en Accordion. El tamaño de letra lo hereda del contenedor, como en 2.0 (para el del cromo, text-callout). Una clase propia (min-h-*) le gana: la regla va en :where(). Sin chevron no trae estilo: lo pone el render.
  • Si hay varias secciones que son un grupo, es un `Accordion`: trae el <h3> por sección.
  • El trigger no trae estilo a propósito: va render={<Button variant="ghost" />}. Con chevron suma el disclosure de iCloud (› que gira a ⌄) y el foco interior.
  • className cae en el contenido, no en el elemento que anima el alto: ahí va el padding.
  • Lo que está plegado no se lee ni se indexa: keepMounted si esos links importan para el crawler.

Relacionados