Bordered group of form fields with the legend riding the border line. Native fieldset and legend semantics, so a screen reader names every control inside with the legend. Reach for it to group related fields inside a longer form; collapsible folds the group and disabled turns off every control at once.
collapsible puts a disclosure button in the legend, and the body unmounts while collapsed. Writing collapsed from script hides or shows the body and emits nothing.
disabled turns off every control in the group at once through the native fieldset, without writing to the children. The disclosure button is exempt, so a disabled group can still be collapsed.
The group is not form associated; the controls inside carry the names and values. A disabled control is barred from submission, so a locked group posts nothing.
// setup(root): properties and events
setup(root) {
const form = root.querySelector('#fs-form');
const out = root.querySelector('#fs-out');
const group = root.querySelector('sui-fieldset');
root.querySelector('#fs-lock').addEventListener('suiChange', (e) => {
group.disabled = e.detail;
});
form.addEventListener('submit', (e) => {
e.preventDefault();
const entries = [...new FormData(form)].map(([k, v]) => `${k}=${v || '(empty)'}`);
out.textContent = entries.length ? entries.join(' ') : 'The form collected nothing.';
});
}
Refusing a collapse
The legend emits suiOpen after expanding and a cancelable suiClose with reason trigger before collapsing. Collapsing unmounts the body and takes the typing with it, so a group of fields is the case that most needs the veto.
Idle.
<div style="display:flex;flex-direction:column;gap:10px;max-width:460px">
<sui-fieldset id="fs-events" collapsible legend="Invoice notes">
<sui-textarea rows="2" name="notes" label="Notes" placeholder="Type here, then try to collapse the group"></sui-textarea>
</sui-fieldset>
<span id="fs-log" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Idle.</span>
</div>
// setup(root): properties and events
setup(root) {
const log = root.querySelector('#fs-log');
const notes = root.querySelector('#fs-events sui-textarea');
const group = root.querySelector('#fs-events');
group.addEventListener('suiClose', (e) => {
if (notes.value) {
e.preventDefault();
log.textContent = `Collapse refused (${e.detail}). The notes are not saved yet.`;
return;
}
log.textContent = `Collapsed (${e.detail}).`;
});
group.addEventListener('suiOpen', () => {
log.textContent = 'Expanded.';
});
}
Keyboard
Key
Action
EnterSpace
On the legend of a collapsible group, toggles the body.
API
<sui-fieldset>
Properties
Property
Attribute
Type
Default
Description
collapsed
collapsed
boolean
false
Whether the body is hidden. Seeds the state (the reference defaultCollapsed) and tracks it afterwards; writing it from script emits nothing.
collapsible
collapsible
boolean
false
Puts a disclosure button with aria-expanded and aria-controls inside the legend. The body closes over --duration-base and unmounts once it has closed. Reflected.
disabled
disabled
boolean
false
Disables every form control inside the group through the native fieldset[disabled] behavior; nothing is written to the children. The disclosure button is exempt (HTML exempts the first legend's descendants), so a disabled group can still be collapsed.
Fires before the legend collapses the body; detail is 'trigger' (the legend is the only way this element closes itself). Cancelable: preventDefault() leaves the group open. A group of fields is the case that most needs the veto, because collapsing unmounts the body and takes the user's typing with it. It does not bubble.
suiOpen
void
onSuiOpen
@sui-open
Fires after the legend expands the body. It does not bubble, as no open-state event does.
Methods
Method
Signature
Description
setFocus()
setFocus() => Promise<void>
Moves keyboard focus to the disclosure button of a collapsible group. Does nothing on a group that does not collapse, which has no tab stop of its own.
Slots
Slot
Description
(default)
Grouped fields.
Types
SuiCloseReasontypeWhy a dismissible surface is closing. Detail of the cancelable suiClose. A consumer expresses "a stray backdrop click must not close this" by calling preventDefault() on the reason it does not accept, which is why none of these needs a prop of its own.
No members.
Theming
Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.