NativeDetails
Native disclosure: `<details>` root, `<summary>` trigger and a content body. 0 kB client JS, at most 0.4 kB gzipped.
Anatomy
<NativeDetails.Root name="faq">
<NativeDetails.Summary>Shipping</NativeDetails.Summary>
<NativeDetails.Content>Ships in 2-3 days.</NativeDetails.Content>
</NativeDetails.Root>Live demo
This demo also runs with JavaScript disabled.
Shipping
Ships in 2-3 days.
Returns
30-day return window.
NativeDetails.Root
Renders <details>. Emits class="uiify-native-details", plus data-disabled="" when disabled.
| Prop | Type | Default | Description |
|---|---|---|---|
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. |
NativeDetails.Summary
Renders <summary>. Emits aria-disabled="true" and tabIndex={-1} when disabled.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | The browser has no native disabled state for `<summary>` — this loses focusability and gets `aria-disabled`. |
NativeDetails.Content
Renders <div> (polymorphic via `as`/`render`). Emits consumer props only.
| Prop | Type | Default | Description |
|---|---|---|---|
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. |
Rendered DOM
<details name="faq" class="uiify-native-details"><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 */
}
.uiify-native-details[data-disabled] > summary {
pointer-events: none; /* the element marks it disabled; blocking the click is your CSS */
}Build your own
import { NativeDetails } from "@gunkin/uiify/elements/native-details";
export function Faq() {
return (
<NativeDetails.Root name="faq">
<NativeDetails.Summary>
What browsers are supported?
<span aria-hidden="true" className="faq-chevron" />
</NativeDetails.Summary>
<NativeDetails.Content>
Every evergreen browser, plus the last two Safari majors.
</NativeDetails.Content>
</NativeDetails.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).
- `NativeDetails.Content` is polymorphic (`as`/`render`) because the disclosure body isn't always a `<div>`.
Import
import { NativeDetails } from "@gunkin/uiify/elements/native-details";