Details
ネイティブの開閉機構。`<details>`のルート、`<summary>`のトリガー、コンテンツ本体。
0 kB client JS≤ 0.4 kB gzipped
Anatomy
<Details.Root name="faq">
<Details.Summary>Shipping</Details.Summary>
<Details.Content>Ships in 2-3 days.</Details.Content>
</Details.Root>Live demo
This demo also runs with JavaScript disabled.
Details
Minimal
Shipping
Ships in 2–3 days.
Composition — exclusive group
Shipping
Ships in 2–3 days.
Returns
30-day return window.
Warranty (unavailable)
Not offered in your region.
Details.Root
Renders <details>. Emits data-uiify-details="", plus data-disabled="" when disabled.
| Name | Type | Default | Notes |
|---|---|---|---|
defaultOpen | boolean | Applies the native `open` attribute on first render. | |
name | string | Groups sibling `<details name>` into an exclusive set. Must be unique per group and stable across SSR. | |
disabled | boolean | Sets `data-disabled` on the root. Blocking the click itself is a CSS responsibility — see the CSS contract below. |
Details.Summary
Renders <summary>. Emits data-part when given; aria-disabled="true" and tabIndex={-1} when disabled.
| Name | Type | Default | Notes |
|---|---|---|---|
disabled | boolean | The browser has no native disabled state for `<summary>` — this loses focusability and gets `aria-disabled`. | |
part | string | Sets `data-part`; omitted when not given, because not every consumer needs one. |
Details.Content
Renders <div> (polymorphic via `as`/`render`). Emits data-part when given.
| Name | Type | Default | Notes |
|---|---|---|---|
as | ElementType | "div" | The disclosure body isn't always a `<div>` — e.g. an `<ol>` for a list. |
render | RenderProp | Escape hatch for a custom element. | |
part | string | Sets `data-part`; omitted when not given. |
Rendered DOM
<details data-uiify-details="" name="faq"><summary>Shipping</summary><div>Ships in 2-3 days.</div></details>CSS contract
details[open] > summary::after {
/* flip a disclosure marker, e.g. rotate an arrow */
}
[data-uiify-details][data-disabled] > summary {
pointer-events: none; /* the element marks it disabled; blocking the click is your CSS */
}Build your own
import { Details } from "@gunkin/uiify/elements/details";
export function Faq() {
return (
<Details.Root name="faq">
<Details.Summary>
What browsers are supported?
<span aria-hidden="true" className="faq-chevron" />
</Details.Summary>
<Details.Content>
Every evergreen browser, plus the last two Safari majors.
</Details.Content>
</Details.Root>
);
}
// details[open] > summary .faq-chevron { transform: rotate(180deg); }
Used by
Gotchas
- `name` groups sibling `<details>` into an exclusive, single-open set with zero JS — it must be unique per group and stable across SSR.
- `disabled` sets `data-disabled`/`aria-disabled`/`tabIndex=-1`, but you still need `pointer-events: none` in your own CSS to actually block the click (see the CSS contract).
- `Details.Content` is polymorphic (`as`/`render`) because the disclosure body isn't always a `<div>`.
Import
import { Details } from "@gunkin/uiify/elements/details";