Fieldset
A group of related form controls, named by a legend.
import { ... } from '@corndev/ui' HTML
No JavaScript required — these classes are the whole component.
<fieldset class="corn-fieldset" data-padding="md" data-variant="default">
<legend class="corn-fieldset-legend">Server</legend>
<input class="corn-input" aria-label="Host" />
</fieldset>
Classes
| Class |
|---|
.corn-fieldset |
.corn-fieldset-legend |
Attributes
| Attribute | Values |
|---|---|
data-padding | none|xs|sm|md|lg|xl |
data-variant | unstyled |
Vanilla JS
Optional. createFieldset only adds and removes the classes and attributes above, so the HTML is equivalent. Reach for it when you need to change options at runtime.
import { createFieldset } from '@corndev/ui';
import '@corndev/ui/theme';
const el = document.querySelector('#target');
const instance = createFieldset(el, { /* options */ });
Options
| Option | Type | Default | Description |
|---|---|---|---|
padding | 'none'|'xs'|'sm'|'md'|'lg'|'xl' | 'md' | Inner spacing. |
variant | 'default'|'unstyled' | 'default' | unstyled drops the border and padding while keeping the grouping semantics, for a group that should not look like a box. |
disabled | boolean | false | Disables every control inside it. This is the native disabled attribute rather than a class, so it really does disable them. |
React
Fieldset — from @corndev/ui-react.
The legend is the legend prop, not a child: <Fieldset legend="Server">. Omitting it renders no <legend> at all rather than an empty one, because an unlabelled group is a legitimate choice and inventing a name would be worse; legend="" renders the element, since an explicit empty label is a different intent.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
legend | React.ReactNode | undefined | Names the group. Omit it for a group that is visual only; nothing is invented in its place. |
padding | 'none'|'xs'|'sm'|'md'|'lg'|'xl' | 'md' | Inner spacing. |
variant | 'default'|'unstyled' | 'default' | unstyled drops the border and padding while keeping the grouping semantics. |
disabled | boolean | false | Disables every control inside it. |
className | string | undefined | Merged with the Corn UI classes. |
children | React.ReactNode | undefined | The controls. |
A form of any size is a set of groups, and the browser already has an element
for that. Fieldset restyles it rather than replacing it, because the two
things it does for free are the two things a div with a heading cannot do:
- a screen reader announces the group and its name when focus enters it
disabledon the group disables every control inside it
React usage
import { Fieldset, Input } from '@corndev/ui-react';
import '@corndev/ui/theme';
<Fieldset legend="Server">
<Input label="Host" />
<Input label="Port" />
</Fieldset>
The legend is a prop, not a child, so the element order is not something you can
get wrong — a <legend> must be the first child of its <fieldset>.
Disabling a whole group
One attribute, and everything inside goes with it:
<Fieldset legend="Authentication" disabled={!enabled}>
<Input label="Client ID" />
<Input label="Client secret" />
<Button>Test connection</Button>
</Fieldset>
This is native behaviour, not a class the library applies: the controls are
genuinely disabled, so they leave the tab order and stop submitting values.
Nothing needs to thread a disabled prop down to each field.
Worth knowing when you assert on it: a control inside a disabled fieldset still
reports input.disabled === false, because that property reflects only its own
attribute. input.matches(':disabled') is the question that gets the right
answer.
A group that should not look like a box
variant="unstyled" keeps the semantics and drops the border and padding:
<Fieldset legend="Visibility" variant="unstyled">
<Radio name="visibility" value="public" label="Public" />
<Radio name="visibility" value="private" label="Private" />
</Fieldset>
Reach for this rather than dropping back to a div — the grouping is worth
keeping even when the box is not.
Vanilla
The markup is the component; createFieldset only restyles what is already
there.
<fieldset class="corn-fieldset" data-padding="md">
<legend class="corn-fieldset-legend">Server</legend>
<input class="corn-input" aria-label="Host" />
</fieldset>
import { createFieldset } from '@corndev/ui';
const group = createFieldset(document.querySelector('fieldset'), { padding: 'lg' });
group.update({ disabled: true });