Ir al contenido

Collapsible

Región que el usuario puede mostrar u ocultar.

Navegadores
Chrome 123+Firefox 121+Safari 17.5+
Nivel
0
Tamaño comprimido
429 B
Presupuesto de diseño forzado
0 ms
Presupuesto de axe
0
Compatible con SSR
Sí
Basado en
elements/details
Contrato publicado
Entorno de pruebas

Zona de pruebas

Collapsible

Closed

Toggle section
Hidden panel content

Open

Toggle section
Visible panel content
import { Collapsible } from "@gunkin/uiify";

export default function Example() {
  return (
    <Collapsible
      className=""
      id="release-notes"
      label="Release notes"
      content={<>New keyboard navigation and accessibility improvements.</>}
    />
  );
}
/* Collapsible — a single native <details>/<summary> disclosure. Same shape
   as accordion.css: [data-part] selectors let styles apply without opting
   into the BEM classes, both rules kept together so they can't drift apart. */

@layer components {
  :where([data-uiify-collapsible], [data-uiify-collapsible]) {
    inline-size: 100%;
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-xl);
    corner-shape: squircle;
    overflow: hidden;
  }

  [data-uiify-collapsible] [data-part="trigger"] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    padding: var(--space-lg);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    cursor: pointer;
    list-style: none;
  }

  [data-uiify-collapsible] [data-part="trigger"]::-webkit-details-marker {
    display: none;
  }

  [data-uiify-collapsible] [data-part="trigger"]:hover {
    background-color: var(--secondary);
  }

  [data-uiify-collapsible] [data-part="trigger"]:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 var(--ring-width) color-mix(in oklch, var(--ring) 16%, transparent);
  }

  [data-uiify-collapsible] [data-part="trigger"]::after {
    content: "+";
    display: grid;
    place-items: center;
    inline-size: 1.5rem;
    block-size: 1.5rem;
    flex: 0 0 1.5rem;
    color: var(--muted-foreground);
    font:
      1.25rem/1 ui-monospace,
      monospace;
    transition: rotate var(--duration-fast) var(--ease-out);
  }

  [data-uiify-collapsible][open] [data-part="trigger"]::after {
    content: "−";
  }

  [data-uiify-collapsible][open] [data-part="trigger"] {
    color: var(--primary);
  }

  [data-uiify-collapsible] [data-part="panel"] {
    padding-block: 0 var(--space-lg);
    padding-inline: var(--space-lg);
    color: var(--muted-foreground);
    font-size: var(--text-sm);
  }

  [data-uiify-collapsible] {
    interpolate-size: allow-keywords;
  }

  :where([data-uiify-collapsible], [data-uiify-collapsible])::details-content {
    block-size: 0;
    overflow: clip;
  }

  :where([data-uiify-collapsible], [data-uiify-collapsible])[open]::details-content {
    block-size: auto;
  }

  /* Shared presence timing; block-size only interpolates where the block above applies. */
  @media (prefers-reduced-motion: no-preference) {
    :where([data-uiify-collapsible], [data-uiify-collapsible])::details-content {
      opacity: 0;
      transition:
        opacity var(--duration-fast) var(--ease-out),
        block-size var(--duration-fast) var(--ease-out),
        content-visibility var(--duration-fast) allow-discrete;
    }

    :where([data-uiify-collapsible], [data-uiify-collapsible])[open]::details-content {
      opacity: 1;
    }
  }
}
import { Collapsible } from "@gunkin/uiify";

export default function Example() {
  return (
    <Collapsible
      className={
        "[inline-size:100%] border-[length:var(--border-width)] border-solid border-border rounded-xl [corner-shape:" +
        "squircle] overflow-hidden [&_[data-part=trigger]]:flex [&_[data-part=trigger]]:items-center [&_[data-part=t" +
        "rigger]]:justify-between [&_[data-part=trigger]]:gap-md [&_[data-part=trigger]]:p-lg [&_[data-part=trigger]" +
        "]:text-sm [&_[data-part=trigger]]:font-[number:var(--weight-medium)] [&_[data-part=trigger]]:cursor-pointer" +
        " [&_[data-part=trigger]]:list-none [&_[data-part=trigger]::-webkit-details-marker]:hidden [&_[data-part=tri" +
        "gger]:hover]:bg-secondary [&_[data-part=trigger]:focus-visible]:[outline:none] [&_[data-part=trigger]:focus" +
        "-visible]:[box-shadow:inset_0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&_[" +
        "data-part=trigger]::after]:content-[\"+\"] [&_[data-part=trigger]::after]:grid [&_[data-part=trigger]::after]" +
        ":place-items-center [&_[data-part=trigger]::after]:[inline-size:1.5rem] [&_[data-part=trigger]::after]:[blo" +
        "ck-size:1.5rem] [&_[data-part=trigger]::after]:[flex:0_0_1.5rem] [&_[data-part=trigger]::after]:text-muted-" +
        "foreground [&_[data-part=trigger]::after]:not-italic [&_[data-part=trigger]::after]:[font-variant:normal] [" +
        "&_[data-part=trigger]::after]:font-normal [&_[data-part=trigger]::after]:[font-stretch:normal] [&_[data-par" +
        "t=trigger]::after]:[font-size:1.25rem] [&_[data-part=trigger]::after]:leading-none [&_[data-part=trigger]::" +
        "after]:[font-family:ui-monospace,_monospace] [&_[data-part=trigger]::after]:[transition:rotate_var(--durati" +
        "on-fast)_var(--ease-out)] [&[open]_[data-part=trigger]::after]:content-[\"−\"] [&[open]_[data-part=trigger]]:" +
        "text-primary [&_[data-part=panel]]:[padding-block:0_var(--space-lg)] [&_[data-part=panel]]:px-lg [&_[data-p" +
        "art=panel]]:text-muted-foreground [&_[data-part=panel]]:text-sm [interpolate-size:allow-keywords] [&::detai" +
        "ls-content]:[block-size:0] [&::details-content]:overflow-clip [&[open]::details-content]:[block-size:auto] " +
        "motion-safe:[&::details-content]:opacity-0 motion-safe:[&::details-content]:[transition:opacity_var(--durat" +
        "ion-fast)_var(--ease-out),_block-size_var(--duration-fast)_var(--ease-out),_content-visibility_var(--durati" +
        "on-fast)_allow-discrete] motion-safe:[&[open]::details-content]:opacity-100"
      }
      id="release-notes"
      label="Release notes"
      content={<>New keyboard navigation and accessibility improvements.</>}
    />
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('[inline-size:100%] border-[length:var(--border-width)] border-solid border-border rounded-xl [corner-shape:squircle] overflow-hidden [&_[data-part=trigger]]:flex [&_[data-part=trigger]]:items-center [&_[data-part=trigger]]:justify-between [&_[data-part=trigger]]:gap-md [&_[data-part=trigger]]:p-lg [&_[data-part=trigger]]:text-sm [&_[data-part=trigger]]:font-[number:var(--weight-medium)] [&_[data-part=trigger]]:cursor-pointer [&_[data-part=trigger]]:list-none [&_[data-part=trigger]::-webkit-details-marker]:hidden [&_[data-part=trigger]:hover]:bg-secondary [&_[data-part=trigger]:focus-visible]:[outline:none] [&_[data-part=trigger]:focus-visible]:[box-shadow:inset_0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&_[data-part=trigger]::after]:content-["+"] [&_[data-part=trigger]::after]:grid [&_[data-part=trigger]::after]:place-items-center [&_[data-part=trigger]::after]:[inline-size:1.5rem] [&_[data-part=trigger]::after]:[block-size:1.5rem] [&_[data-part=trigger]::after]:[flex:0_0_1.5rem] [&_[data-part=trigger]::after]:text-muted-foreground [&_[data-part=trigger]::after]:not-italic [&_[data-part=trigger]::after]:[font-variant:normal] [&_[data-part=trigger]::after]:font-normal [&_[data-part=trigger]::after]:[font-stretch:normal] [&_[data-part=trigger]::after]:[font-size:1.25rem] [&_[data-part=trigger]::after]:leading-none [&_[data-part=trigger]::after]:[font-family:ui-monospace,_monospace] [&_[data-part=trigger]::after]:[transition:rotate_var(--duration-fast)_var(--ease-out)] [&[open]_[data-part=trigger]::after]:content-["−"] [&[open]_[data-part=trigger]]:text-primary [&_[data-part=panel]]:[padding-block:0_var(--space-lg)] [&_[data-part=panel]]:px-lg [&_[data-part=panel]]:text-muted-foreground [&_[data-part=panel]]:text-sm [interpolate-size:allow-keywords] [&::details-content]:[block-size:0] [&::details-content]:overflow-clip [&[open]::details-content]:[block-size:auto] motion-safe:[&::details-content]:opacity-0 motion-safe:[&::details-content]:[transition:opacity_var(--duration-fast)_var(--ease-out),_block-size_var(--duration-fast)_var(--ease-out),_content-visibility_var(--duration-fast)_allow-discrete] motion-safe:[&[open]::details-content]:opacity-100');

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

Collapsible

PropTipoPredeterminadoDescripción
id*string—Id del elemento <details> subyacente.
label*ReactNode—Contenido de summary que abre y cierra la región.
content*ReactNode—Contenido del panel que se muestra al abrir la región.
defaultOpenbooleanfalseEstado abierto en el primer renderizado. Es no controlado, por lo que se conserva sin JavaScript.
disabledbooleanfalseBloquea el cambio de estado y marca summary con aria-disabled y data-disabled.
classNamestring—Clase aplicada a la raíz <details>.

Teclado

TeclaAcción
TabLlevar el foco al control o sacarlo de él
Enter / SpaceActivar cuando tiene el foco (controles de tipo botón)

Accesibilidad

Usa HTML semántico siempre que es posible. Inspecciona el marcado renderizado en el entorno de pruebas: ARIA se añade solo cuando los elementos nativos no bastan.

Puntos de estilo

data-disabled