Theme
Version
GitHub PyPI Discord
On this page

Select

Use CSelect when people choose one value and the collection should remain compact until opened. The component progressively enhances a native Select, so form submission and reset retain native behavior.

Select at a glance

Select at a glance
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class SelectAtAGlance(Component):
    template = """
      <c-CField>
        <c-fill name="label">Workspace</c-fill>
        <c-fill name="description">Choose where new observations belong.</c-fill>
        <c-fill name="default">
          <c-CSelect c-options="options" placeholder="Choose a workspace" value="atlas" />
        </c-fill>
      </c-CField>
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {
            "options": [
                CSelectOption("atlas", "Atlas research", "12 collaborators"),
                CSelectOption("aurora", "Aurora field notes", "7 collaborators"),
                CSelectOption("archive", "Archived studies", disabled=True),
            ]
        }


preview = SelectAtAGlance()
preview  # noqa: B018

Submit a value

Submit a Select
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class SelectForm(Component):
    template = """
      <form x-data @submit.prevent="result = Array.from(new FormData($event.target).entries())">
        <c-CField required>
          <c-fill name="label">Review status</c-fill>
          <c-fill name="default">
            <c-CSelect c-options="options" placeholder="Choose a status" name="status" />
          </c-fill>
        </c-CField>
        <c-CButton type="submit">Save</c-CButton>
        <c-CButton type="reset" variant="ghost">Reset</c-CButton>
        <output x-text="JSON.stringify(result)"></output>
      </form>
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {"options": [CSelectOption("draft", "Draft"), CSelectOption("review", "Ready for review")]}


preview = SelectForm()
preview  # noqa: B018
Group options
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class GroupedSelect(Component):
    template = """
      <c-CSelect
        c-options="options"
        placeholder="Choose a destination"
        c-trigger_attrs="{'aria-label':'Destination'}"
      />
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {
            "options": [
                CSelectOption("oslo", "Oslo", group="Europe"),
                CSelectOption("prague", "Prague", group="Europe"),
                CSelectOption("kyoto", "Kyoto", group="Asia"),
                CSelectOption("seoul", "Seoul", group="Asia"),
            ]
        }


preview = GroupedSelect()
preview  # noqa: B018

Control selection

Control selection
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class ControlledSelect(Component):
    template = """
      <div x-data>
        <c-CSelect
          c-options="options"
          placeholder="Choose a status"
          value="draft"
          c-trigger_attrs="{'aria-label':'Status'}"
          $c-props="{
            value:$store.selectExample.value,
            onValueChange:(next) => $store.selectExample.value = next,
          }"
        />
        <p>Current: <strong x-text="$store.selectExample.value"></strong></p>
      </div>
    """
    js = "Alpine.store('selectExample', {value:'draft'});"

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {"options": [CSelectOption("draft", "Draft"), CSelectOption("published", "Published")]}


preview = ControlledSelect()
preview  # noqa: B018

Read-only and disabled states

Select states
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class SelectStates(Component):
    template = """
      <c-CStack>
        <c-CSelect
          c-options="options" placeholder="Choose" value="active" readonly
          c-trigger_attrs="{'aria-label':'Read-only state'}"
        />
        <c-CSelect
          c-options="options" placeholder="Choose" disabled
          c-trigger_attrs="{'aria-label':'Disabled state'}"
        />
        <c-CSelect c-options="options" placeholder="Choose" invalid c-trigger_attrs="{'aria-label':'Invalid state'}" />
      </c-CStack>
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {"options": [CSelectOption("active", "Active"), CSelectOption("paused", "Paused")]}


preview = SelectStates()
preview  # noqa: B018

Variants and sizes

Select variants and sizes
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class SelectVariants(Component):
    template = """
      <c-CStack>
        <c-CSelect
          c-options="options" placeholder="Outline" variant="outline" size="sm"
          c-trigger_attrs="{'aria-label':'Small outline'}"
        />
        <c-CSelect
          c-options="options" placeholder="Filled" variant="filled"
          c-trigger_attrs="{'aria-label':'Medium filled'}"
        />
        <c-CSelect
          c-options="options" placeholder="Plain" variant="plain" size="lg"
          c-trigger_attrs="{'aria-label':'Large plain'}"
        />
      </c-CStack>
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {"options": [CSelectOption("one", "One"), CSelectOption("two", "Two")]}


preview = SelectVariants()
preview  # noqa: B018

Keyboard behavior

Enter, Space, Down, or Up opens the Listbox. Down and Up move the highlight; Home and End jump to its edges; printable text performs buffered typeahead; Enter or Space commits; Escape closes unchanged; and Tab closes while ordinary page navigation continues.

Navigate Select
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class KeyboardSelect(Component):
    template = """
      <c-CSelect
        c-options="options"
        placeholder="Focus and use the keyboard"
        loop
        c-trigger_attrs="{'aria-label':'Planet keyboard example'}"
      />
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {
            "options": [
                CSelectOption("earth", "Earth"),
                CSelectOption("mars", "Mars"),
                CSelectOption("jupiter", "Jupiter"),
            ]
        }


preview = KeyboardSelect()
preview  # noqa: B018

Customize Select

Customize Select
Show code
import citry_ui
from citry import Component, citry
from citry_ui import CSelectOption

citry.register_library(citry_ui)


class CustomizedSelect(Component):
    css = """
      .brand-select {
        --cui-select-radius: 1rem;
        --cui-select-selected-background: #53389e;
        --cui-select-selected-foreground: white;
        --cui-select-focus-color: #7f56d9;
        inline-size: min(100%, 22rem);
      }
    """
    template = """
      <c-CSelect
        class_="brand-select"
        c-options="options"
        placeholder="Choose a collection"
        c-trigger_attrs="{'aria-label':'Collection'}"
      />
    """

    def template_data(self, _kwargs: object, _slots: object) -> dict[str, object]:
        return {"options": [CSelectOption("botany", "Botany"), CSelectOption("astronomy", "Astronomy")]}


preview = CustomizedSelect()
preview  # noqa: B018

Accessibility and forms

The visible Button uses the select-only combobox pattern and keeps DOM focus while aria-activedescendant identifies the highlighted Option. A native Select remains the form value, validity, and reset truth. Before client initialization, that native control is the visible fallback.

Use CListbox for a persistent collection, CMultiSelect for several compact values, and CCombobox when users need text filtering or custom input.

API reference

Inputs

CSelect server inputs

Server inputs are passed in a template through <c-CSelect ... /> or in Python through CSelect(...).

InputTypeDefaultEffect
optionsSequence[CSelectOption]requiredSupplies the nonempty ordered stable collection.
placeholderstrrequiredSupplies author-localized empty-value text.
namestr | NoneNoneSets the native form field name.
formstr | NoneNoneAssociates the native value proxy with a Form ID.
idstr | NoneNoneSets native proxy identity and generated relationships.
valuestr | NoneNoneSets the initial selected stable value.
openboolFalseSets initial popup visibility when eligible.
requiredbool | NoneNoneEnables native required validity outside Field.
disabledbool | NoneNoneDisables selection and form contribution.
readonlybool | NoneNonePreserves submission while preventing changes.
invalidbool | NoneNoneAdds owner-supplied invalid presentation.
loopboolFalseWraps open Listbox arrow navigation.
placement"bottom-start" | "bottom-end" | "top-start" | "top-end" (CSelectPlacement)"bottom-start"Sets preferred logical popup placement.
match_widthboolTrueMatches the popup inline size to the control within viewport limits.
variant"outline" | "filled" | "plain" (CSelectVariant)"outline"Selects control treatment.
size"sm" | "md" | "lg" (CSelectSize)"md"Selects control and Option geometry.
class_CClassValue | None (CClassValue)NoneAdds root classes.
styleCStyleValue | None (CStyleValue)NoneAdds root inline styles.
attrsMapping[str, object] | NoneNoneAdds trusted nonconflicting root attributes.
trigger_attrsMapping[str, object] | NoneNoneAdds trusted relationships events and accessible naming to the combobox Button.
listbox_attrsMapping[str, object] | NoneNoneAdds trusted nonconflicting Listbox attributes.

CSelect client inputs

Client inputs are passed in the browser through the $c-props="{ ... }" attribute on <c-CSelect />.

InputTypeOmitted behaviorEffect
valuestring | nullReleases control to committed selection.Controls selected value while supplied.
openboolean | nullReleases control to committed visibility.Controls popup visibility while supplied.
requiredboolUses the server or Field fallback.Reactively changes required validity.
disabledboolUses the server or Field fallback.Reactively disables selection.
readonlyboolUses the server or Field fallback.Reactively prevents changes while preserving submission.
invalidboolUses the server or Field fallback.Reactively changes invalid presentation.
loopboolUses the server value.Reactively changes arrow wrapping.
placementCSelectPlacementUses the server value.Reactively changes preferred placement.
matchWidthboolUses the server value.Reactively changes popup sizing.
variantCSelectVariantUses the server value.Reactively changes treatment.
sizeCSelectSizeUses the server value.Reactively changes geometry.
onValueChange((value: string | null, detail: CSelectValueChangeDetail) => void) | undefinedNo component callback runs.Receives selection reset and structural requests.
onOpenChange((open: boolean, detail: CSelectOpenChangeDetail) => void) | undefinedNo component callback runs.Receives visibility requests and forced-close notices.

Slots

-

Events

Component events are callback inputs supplied through $c-props. Native browser events remain available through Alpine @... attributes.

CSelect events

EventSignatureTrigger and timingDetailControlled and cancellation behavior
onValueChange(value: string | null, detail: CSelectValueChangeDetail) => void (CSelectValueChangeDetail)Enabled selection reset or structural recovery.{value, previousValue, option, controlled, source, sourceEvent} (CSelectValueChangeDetail)Commits immediately when uncontrolled and waits for owner acceptance when controlled.
onOpenChange(open: boolean, detail: CSelectOpenChangeDetail) => void (CSelectOpenChangeDetail)Visibility request or nonrejectable safety close.{open, reason, controlled, forced, source} (CSelectOpenChangeDetail)Controlled requests notify without changing visibility; forced safety closes always hide.

Methods

-

CSS

CSS variables to theme the components. Set them on an ancestor or the component itself.

CSelect CSS variables

Apply these variables to CSelect or one of its ancestors.

VariableTypePurposeDefault
--cui-select-backgroundcolorControl and popup surface.Canvas
--cui-select-foregroundcolorPrimary foreground.CanvasText
--cui-select-placeholder-colorcolorEmpty-value foreground.scheme-aware muted
--cui-select-muted-colorcolorDescription and disabled foreground.scheme-aware muted
--cui-select-border-colorcolorOutline border.scheme-aware subtle border
--cui-select-hover-backgroundcolorHighlighted Option surface.CanvasText mix
--cui-select-selected-backgroundcolorSelected Option surface.scheme-aware blue
--cui-select-selected-foregroundcolorSelected Option foreground.scheme-aware blue text
--cui-select-focus-colorcolorFocus outline.Highlight
--cui-select-radiuslengthControl and popup corners.0.625rem
--cui-select-control-paddinglengthControl padding.size-derived
--cui-select-option-paddinglengthOption padding.size-derived
--cui-select-max-block-sizelengthPopup scroll boundary.18rem
--cui-select-offsetlengthAnchor gap.0.25rem
--cui-select-shadowshadowPopup elevation.scheme-aware shadow
--cui-select-durationtimePopup and indicator motion.120ms

Attributes

HTML attributes defined on the components that you can refer to for CSS, inspection, and testing. Read-only.

CSelect attributes

AttributeElementTypeMeaning
roleControl ButtoncomboboxDeclares the select-only popup control.
roleListbox divlistboxDeclares the popup collection.
roleOption divoptionDeclares each value.
aria-expandedControl Buttontrue | falseReflects popup visibility.
aria-controlsControl ButtonIDREFTargets the Listbox.
aria-activedescendantControl ButtonIDREF or absentIdentifies the highlighted open Option.
aria-requiredControl Buttontrue or absentMirrors effective required state.
aria-disabledControl Buttontrue or absentMirrors effective unavailability.
aria-readonlyControl Buttontrue or absentMirrors read-only interaction.
aria-invalidControl Buttontrue or absentMirrors effective invalid presentation.
aria-selectedOption divtrue | falseReflects effective selection.
data-openRoot divpresent-or-absentMirrors effective visibility.
data-emptyRoot divpresent-or-absentMirrors no selected value.
data-requiredRoot divpresent-or-absentMirrors effective required state.
data-readonlyRoot divpresent-or-absentMirrors read-only interaction.
data-invalidRoot divpresent-or-absentMirrors effective invalid presentation.
data-match-widthRoot divpresent-or-absentMirrors popup width matching.
data-variantRoot divoutline | filled | plainMirrors effective treatment.
data-sizeRoot divsm | md | lgMirrors effective geometry.
data-valueOption divstringExposes stable identity.
data-selectedOption divpresent-or-absentMirrors selection.
data-highlightedOption divpresent-or-absentMirrors active descendant.
data-disabledRoot or Option divpresent-or-absentMirrors effective unavailability.
data-placementPopup divCSelectPlacementReflects preferred logical placement.

Selectors

Selectors for the DOM nodes in the components that you can use for CSS, inspection, and testing.

CSelect selectors

SelectorElementPurpose
[data-citry-ui-part="root"]Root divStable root attrs and state surface.
[data-citry-ui-part="control"]Combobox ButtonVisible control and focus owner.
[data-citry-ui-part="value"]Value spanSelected label or placeholder.
[data-citry-ui-part="indicator"]Indicator spanDecorative popup-state mark.
[data-citry-ui-part="popup"]Manual popover divTop-layer scrolling surface.
[data-citry-ui-part="listbox"]Listbox divSemantic collection.
[data-citry-ui-part="group"]Group divRelated Options.
[data-citry-ui-part="group-label"]Group label spanVisible group name.
[data-citry-ui-part="option"]Option divValue semantics and state.
[data-citry-ui-part="option-label"]Option label spanAccessible Option name.
[data-citry-ui-part="option-description"]Option description spanSupporting description.

Interfaces

Aliases and data shapes referenced above.

Input type aliases

InterfaceDefinition
CClassValuestr | Mapping[str, bool] | Sequence[CClassValue]
CStyleValuestr | Mapping[str, object] | Sequence[CStyleValue]
CSelectPlacementLiteral["bottom-start", "bottom-end", "top-start", "top-end"]
CSelectVariantLiteral["outline", "filled", "plain"]
CSelectSizeLiteral["sm", "md", "lg"]
CSelectChangeSourceLiteral["pointer", "keyboard", "reset", "structure"]
CSelectOpenReasonLiteral["trigger", "keyboard", "selection", "escape", "tab", "outside", "focus-outside", "reset", "native", "ancestor"]

CSelectOption

FieldTypeDefaultMeaning
valuestr-Stable unique form value.
labelstr-Visible accessible Option name.
descriptionstr | None-Optional separately described supporting text.
disabledbool-Prevents user selection.
groupstr | None-Optional contiguous visible group label.

CSelectValueChangeDetail

FieldTypeDefaultMeaning
valuestr | None-Requested value.
previousValuestr | None-Previous effective value.
optionHTMLElement | None-Activated Option or None for reset and structure.
controlledbool-Whether client value owns selection.
sourceCSelectChangeSource-Request source.
sourceEventEvent | None-Native source event when present.

CSelectOpenChangeDetail

FieldTypeDefaultMeaning
openbool-Requested or forced visibility.
reasonCSelectOpenReason-Visibility reason.
controlledbool-Whether client open owns visibility.
forcedbool-Whether safety made the close nonrejectable.
sourceEventTarget | None-Native source or safety owner.

Translation keys

-