Conditional Fields
stimeo--conditional-fields
Shows/hides and enables/disables regions based on a trigger control's value.
The stimeo--conditional-fields controller watches trigger controls and shows or hides regions whose condition holds, keeping hidden, aria-hidden, and disabled in sync. Each region declares its condition with data-when-checked, data-when-unchecked, or data-when-value="x"; with multiple triggers, match (any/all) combines them. While hidden, a region's inputs are disabled (when disableHidden) so they drop out of the submission, and hiding a region that holds focus first retreats focus to a trigger. It re-derives state from the triggers on connect (Morph-safe) and dispatches stimeo--conditional-fields:change. Behavior only — no styling is applied.
<%# Conditional fields demo: check the box to reveal the address fieldset. The
controller toggles hidden / aria-hidden and disables the hidden inputs (so they
drop out of submission); it listens for the change itself, so no consumer JS is
needed. This demo only styles the layout. %>
<div class="conditional-fields-demo">
<form data-controller="stimeo--conditional-fields">
<label class="conditional-fields-demo__toggle">
<input type="checkbox" data-stimeo--conditional-fields-target="trigger">
<%= t("components.conditional_fields.demo.toggle") %>
</label>
<fieldset
class="conditional-fields-demo__region"
data-stimeo--conditional-fields-target="region"
data-when-checked
hidden>
<legend><%= t("components.conditional_fields.demo.legend") %></legend>
<label class="conditional-fields-demo__field">
<span><%= t("components.conditional_fields.demo.street") %></span>
<input type="text" name="street">
</label>
<label class="conditional-fields-demo__field">
<span><%= t("components.conditional_fields.demo.city") %></span>
<input type="text" name="city">
</label>
</fieldset>
</form>
</div>
/*
* Presentation-only styles for the conditional-fields demo.
* The library toggles hidden / aria-hidden / disabled and data-visible; this CSS
* only lays out the toggle and the revealed fieldset.
*/
.conditional-fields-demo {
max-width: 28rem;
}
.conditional-fields-demo form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.conditional-fields-demo__toggle {
display: flex;
align-items: center;
gap: 0.5rem;
}
.conditional-fields-demo__region {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin: 0;
padding: 1rem;
border: 1px solid var(--border);
border-radius: 0.5rem;
}
.conditional-fields-demo__field {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.conditional-fields-demo__field input {
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.375rem;
font: inherit;
}
This demo needs no consumer-side JS (the controller handles the behavior).
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--conditional-fields"
Targets
| Name | Description | Attribute |
|---|---|---|
trigger
required
|
Control(s) whose value/checked state drives the regions. | data-stimeo--conditional-fields-target="trigger" |
region
required
|
Element shown/hidden by its data-when-* condition. |
data-stimeo--conditional-fields-target="region" |
Values
| Name | Description | Attribute |
|---|---|---|
disableHidden
|
Disable inputs inside a hidden region so they are not submitted (default true). |
data-stimeo--conditional-fields-disable-hidden-value |
match
|
How multiple triggers combine: any or all (default any). |
data-stimeo--conditional-fields-match-value |
Actions
| Name | Action |
|---|---|
evaluate
|
stimeo--conditional-fields#evaluate |
Events
| Name | Description | Event |
|---|---|---|
change
|
Fires when a region's visibility changes, with detail.region / detail.visible. |
stimeo--conditional-fields:change |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
hidden / aria-hidden |
Region | Added while the region's condition does not hold. |
disabled |
Inputs inside a hidden region | Added (when disableHidden) so they drop out of the submission. |
data-visible |
Region | Present while the region is shown. |