Select
<oblyx-select> is a labeled dropdown composed with <oblyx-option> children, one per row. Underneath its custom trigger it mirrors those children into a real, visually hidden native <select>, so the control participates in native HTML form submission and constraint validation with zero consumer JavaScript. There is deliberately no wrapper field element: label, help and error are plain attributes on oblyx-select itself.
Basic select
<oblyx-select label="Country" placeholder="Select a country">
<oblyx-option value="ca">Canada</oblyx-option>
<oblyx-option value="us">United States</oblyx-option>
<oblyx-option value="mx">Mexico</oblyx-option>
</oblyx-select>oblyxSelect(label = "Country", placeholder = "Select a country") {
oblyxOption(value = "ca") { +"Canada" }
oblyxOption(value = "us") { +"United States" }
oblyxOption(value = "mx") { +"Mexico" }
}Options and selection
Each <oblyx-option> contributes a value and a label: its rendered content, unless an explicit label attribute overrides it. value on oblyx-select seeds which option starts selected: it must match an oblyx-option value to have any visible effect. After that first render the select owns its own selection, the same way a native <select> owns selectedIndex; it fires a bubbling change event on every choice a reader makes.
Select with a preselected value
<oblyx-select label="Country" value="us">
<oblyx-option value="ca">Canada</oblyx-option>
<oblyx-option value="us">United States</oblyx-option>
<oblyx-option value="mx">Mexico</oblyx-option>
</oblyx-select>oblyxSelect(label = "Country", value = "us") {
oblyxOption(value = "ca") { +"Canada" }
oblyxOption(value = "us") { +"United States" }
oblyxOption(value = "mx") { +"Mexico" }
}An option can also be disabled. A disabled option is skipped by keyboard navigation, typeahead and click, and rendered disabled on the hidden native mirror <option> too.
Select with a disabled option
<oblyx-select label="Seat" placeholder="Select a seat">
<oblyx-option value="1a">1A</oblyx-option>
<oblyx-option value="1b" disabled>1B (occupied)</oblyx-option>
<oblyx-option value="1c">1C</oblyx-option>
</oblyx-select>oblyxSelect(label = "Seat", placeholder = "Select a seat") {
oblyxOption(value = "1a") { +"1A" }
oblyxOption(value = "1b", disabled = true) { +"1B (occupied)" }
oblyxOption(value = "1c") { +"1C" }
}Sizes
Select sizes
<oblyx-select label="Small" size="sm">
<oblyx-option value="a">Option A</oblyx-option>
</oblyx-select>
<oblyx-select label="Medium" size="md">
<oblyx-option value="a">Option A</oblyx-option>
</oblyx-select>
<oblyx-select label="Large" size="lg">
<oblyx-option value="a">Option A</oblyx-option>
</oblyx-select>oblyxSelect(label = "Small", size = OblyxSelectSize.SM) {
oblyxOption(value = "a") { +"Option A" }
}
oblyxSelect(label = "Medium", size = OblyxSelectSize.MD) {
oblyxOption(value = "a") { +"Option A" }
}
oblyxSelect(label = "Large", size = OblyxSelectSize.LG) {
oblyxOption(value = "a") { +"Option A" }
}Disabled
Forwarded to both the visible trigger button and the hidden native mirror <select>.
Disabled select
<oblyx-select label="Country" value="us" disabled>
<oblyx-option value="us">United States</oblyx-option>
</oblyx-select>oblyxSelect(label = "Country", value = "us", disabled = true) {
oblyxOption(value = "us") { +"United States" }
}Error
Setting error puts the control in its error visual state and sets aria-invalid="true" on the trigger; non-empty text is also rendered. This is purely informational and does not call setCustomValidity.
Select with error
<oblyx-select label="Country" placeholder="Select a country" error="Choose a country to continue.">
<oblyx-option value="ca">Canada</oblyx-option>
<oblyx-option value="us">United States</oblyx-option>
</oblyx-select>oblyxSelect(label = "Country", placeholder = "Select a country", error = "Choose a country to continue.") {
oblyxOption(value = "ca") { +"Canada" }
oblyxOption(value = "us") { +"United States" }
}Form submission and validation
name on oblyx-select is what makes the chosen option's value appear in FormData under that key: it is forwarded to the hidden native <select name>, not the visible trigger. required forwards to that same native select, so the browser's own "please select an item" validation blocks submission and reports validity, unlike an <input type="hidden"> mirror, which the HTML spec bars from constraint validation entirely.
Select inside a form
Submit without choosing a country to see native validation block it.
<form onsubmit="event.preventDefault(); const data = new FormData(this); this.querySelector('output').textContent = 'country = ' + data.get('country');">
<oblyx-select label="Country" name="country" placeholder="Select a country" required>
<oblyx-option value="ca">Canada</oblyx-option>
<oblyx-option value="us">United States</oblyx-option>
<oblyx-option value="mx">Mexico</oblyx-option>
</oblyx-select>
<button type="submit">Continue</button>
<output></output>
</form>form {
oblyxSelect(label = "Country", name = "country", placeholder = "Select a country", required = true) {
oblyxOption(value = "ca") { +"Canada" }
oblyxOption(value = "us") { +"United States" }
oblyxOption(value = "mx") { +"Mexico" }
}
button(type = ButtonType.submit) { +"Continue" }
}Reference
<oblyx-select>
| Attribute | Type | Default | Description |
|---|---|---|---|
label | string | undefined | – | Label text, always rendered and associated with the trigger via a real <label for>. This works even though the trigger is a <button>, not an <input>: <button> is a "labelable" element per the HTML spec, so the browser's own accessible-name computation resolves a <label for> pointing at it exactly like it would for oblyx-input. Required for an accessible name; omitting it is a defect and is flagged loudly. |
help | string | undefined | – | Help text, rendered between the label and the control and wired into the trigger's aria-describedby. |
error | string | undefined | – | Error message. Presence alone puts the control in its error visual state and sets aria-invalid="true" on the trigger; non-empty text is also rendered and wired into aria-describedby, mirroring oblyx-input's error contract exactly. |
size | smmdlg | md | Form-control height. |
name | string | undefined | – | Forwarded verbatim to the native <select name>. This is what makes the value appear in FormData/receiveParameters(). |
value | string | undefined | – | Initial selected value only. Seeds the first render rather than acting as a fully-controlled value. Must match an <oblyx-option value> to have any visible effect. |
placeholder | string | undefined | Select… | Shown in the trigger when nothing is selected. |
required | boolean | false | Forwarded to the native mirror <select required>, enforcing real constraint validation via a real <select> rather than a hidden input. |
disabled | boolean | false | Native disabled state, forwarded to both the trigger button and the native mirror <select>. |
Events
| Event | Type | Description |
|---|---|---|
change | Event |
<oblyx-option>
| Attribute | Type | Default | Description |
|---|---|---|---|
value | string | undefined | – | The value this option contributes to the select. Required, like a native <option value>. Missing it is a defect and is flagged loudly rather than silently omitting the row from <oblyx-select>'s model. |
label | string | undefined | – | Optional explicit label for the trigger's collapsed display and the hidden native <select> mirror's <option> text. Falls back to the rendered content, since that is what is visually true for a light-DOM row that may contain more than plain text. See displayLabel. |
disabled | boolean | false | Forwarded to the native mirror <option disabled> and to this row's own aria-disabled/click handling. A disabled option is skipped by keyboard navigation, typeahead and click. |
selected | boolean | false | Driven by the parent <oblyx-select>, true for the one row whose value matches the select's current value. Reflected so oblyx-option[selected] is a CSS hook, and so an author can pre-select a row with a plain selected attribute the same way a native <option selected> works. |
highlighted | boolean | false | Driven by the parent <oblyx-select>, true for the row the keyboard/mouse cursor currently rests on. Purely visual; aria-activedescendant on the trigger is the real accessibility signal, this is just its CSS-visible counterpart. |