New components library - Native UI

Field

Combine labels, controls, and help text to compose accessible form fields and grouped inputs.

Installation

Copy the following code into your app directory.

uv

uv run buridan add component field
from components.ui.field import field

Composition

field.root

A single control with label, helper text, and validation.

field.root
├── field.label
├── Input / Textarea / switch.root / select.root
├── field.description
└── field.error

field.group

Related fields in one group. Use field.separator between sections when needed.

field.group
├── field.root
│   ├── field.label
│   ├── Input / Textarea / switch.root / select.root
│   ├── field.description
│   └── field.error
├── field.separator
└── field.root
    ├── field.label
    └── Input / Textarea / switch.root / select.root

field.set

Semantic grouping with a legend and description, usually containing a field.group.

field.set
├── field.legend
├── field.description
└── field.group
    ├── field.root
    │   ├── field.label
    │   ├── Input / Textarea / switch.root / select.root
    │   ├── field.description
    │   └── field.error
    └── field.root
        ├── field.label
        └── Input / Textarea / switch.root / select.root

Anatomy

Use the following composition to build a Field component.

field.root( field.content( field.label(), field.title(), field.description(), ), field.error(), )
  • field.root is the core wrapper for a single field.

  • field.content is a flex column that groups label and description. Not required if you have no description.

  • Wrap related fields with field.group, and use field.set with field.legend for semantic grouping.

Examples

General

Payment Method

All transactions are secure and encrypted

Enter your 16-digit card number

Billing Address

The billing address associated with your payment method

import reflex as rx

from components.ui.button import button
from components.ui.checkbox import checkbox
from components.ui.field import field
from components.ui.input import input
from components.ui.select import select
from components.ui.textarea import textarea

months = [
    {"label": "MM", "value": ""},
    {"label": "01", "value": "01"},
    {"label": "02", "value": "02"},
    {"label": "03", "value": "03"},
    {"label": "04", "value": "04"},
    {"label": "05", "value": "05"},
    {"label": "06", "value": "06"},
    {"label": "07", "value": "07"},
    {"label": "08", "value": "08"},
    {"label": "09", "value": "09"},
    {"label": "10", "value": "10"},
    {"label": "11", "value": "11"},
    {"label": "12", "value": "12"},
]

years = [
    {"label": "YYYY", "value": ""},
    {"label": "2024", "value": "2024"},
    {"label": "2025", "value": "2025"},
    {"label": "2026", "value": "2026"},
    {"label": "2027", "value": "2027"},
    {"label": "2028", "value": "2028"},
    {"label": "2029", "value": "2029"},
]


def field_demo() -> rx.Component:
    return rx.el.div(
        rx.el.form(
            field.group(
                field.set(
                    field.legend("Payment Method"),
                    field.description("All transactions are secure and encrypted"),
                    field.group(
                        field.root(
                            field.label("Name on Card", html_for="checkout-card-name"),
                            input(
                                id="checkout-card-name",
                                placeholder="Evil Rabbit",
                                required=True,
                            ),
                        ),
                        field.root(
                            field.label("Card Number", html_for="checkout-card-number"),
                            input(
                                id="checkout-card-number",
                                placeholder="1234 5678 9012 3456",
                                required=True,
                            ),
                            field.description("Enter your 16-digit card number"),
                        ),
                        rx.el.div(
                            field.root(
                                field.label("Month", html_for="checkout-exp-month"),
                                select.root(
                                    select.trigger(
                                        select.value(),
                                        select.icon(),
                                        id="checkout-exp-month",
                                    ),
                                    select.portal(
                                        select.positioner(
                                            select.popup(
                                                select.group(
                                                    *[
                                                        select.item(
                                                            select.item_text(
                                                                item["label"]
                                                            ),
                                                            select.item_indicator(),
                                                            value=item["value"],
                                                        )
                                                        for item in months
                                                    ]
                                                )
                                            )
                                        )
                                    ),
                                    items=months,
                                    default_value="MM",
                                ),
                            ),
                            field.root(
                                field.label("Year", html_for="checkout-exp-year"),
                                select.root(
                                    select.trigger(
                                        select.value(),
                                        select.icon(),
                                        id="checkout-exp-year",
                                    ),
                                    select.portal(
                                        select.positioner(
                                            select.popup(
                                                select.group(
                                                    *[
                                                        select.item(
                                                            select.item_text(
                                                                item["label"]
                                                            ),
                                                            select.item_indicator(),
                                                            value=item["value"],
                                                        )
                                                        for item in years
                                                    ]
                                                )
                                            )
                                        )
                                    ),
                                    items=years,
                                    default_value="YYYY",
                                ),
                            ),
                            field.root(
                                field.label("CVV", html_for="checkout-cvv"),
                                input(
                                    id="checkout-cvv",
                                    placeholder="123",
                                    required=True,
                                ),
                            ),
                            class_name="grid grid-cols-3 gap-4",
                        ),
                    ),
                ),
                field.separator(),
                field.set(
                    field.legend("Billing Address"),
                    field.description(
                        "The billing address associated with your payment method"
                    ),
                    field.group(
                        field.root(
                            checkbox.root(
                                checkbox.indicator(),
                                id="checkout-same-as-shipping",
                                default_checked=True,
                            ),
                            field.label(
                                "Same as shipping address",
                                html_for="checkout-same-as-shipping",
                                class_name="font-normal",
                            ),
                            orientation="horizontal",
                        )
                    ),
                ),
                field.set(
                    field.group(
                        field.root(
                            field.label("Comments", html_for="checkout-comments"),
                            textarea(
                                id="checkout-comments",
                                placeholder="Add any additional comments",
                                class_name="resize-none",
                            ),
                        )
                    )
                ),
                field.root(
                    button("Submit", type="submit"),
                    button("Cancel", variant="outline", type="button"),
                    orientation="horizontal",
                ),
            )
        ),
        class_name="w-full max-w-md my-10",
    )

Responsive Layout

  • Vertical fields: Default orientation stacks label, control, and helper text—ideal for mobile-first layouts.

  • Horizontal fields: Set orientation="horizontal" on field.root to align the label and control side-by-side. Pair with field.content to keep descriptions aligned.

  • Responsive fields: Set orientation="responsive" for automatic column layouts inside container-aware parents.

Validation and Errors

  • Add data_invalid="true" to field.root to switch the entire block into an error state.

  • Add aria_invalid="true" on the input itself for assistive technologies.

  • Render field.error immediately after the control or inside field.content to keep error messages aligned with the field.

field.root(
    field.label("Email", html_for="email"),
    input(id="email", type="email", aria_invalid="true"),
    field.error("Enter a valid email address."),
    data_invalid="true",
)

API Reference

field.set

Container that renders a semantic fieldset with spacing presets.

PropTypeDefault
class_namestr
field.set_(
    field.legend("Delivery"),
    field.group(),
)

field.legend

Legend element for a field.set_. Switch to the "label" variant to align with standard label sizing.

PropTypeDefault
variant`"legend""label"`
class_namestr
field.legend("Notification Preferences", variant="label")

The field.legend has two variants: legend and label. The label variant applies standard input label sizing and alignment, which is useful if you are stacking nested fieldsets.

field.group

Layout wrapper that stacks field.root components and enables container queries for responsive orientations.

PropTypeDefault
class_namestr
field.group(
    field.root(),
    field.root(),
    class_name="@container/field-group flex flex-col gap-6",
)

field.root

The core wrapper for a single field. Provides orientation control, invalid state styling, and spacing configurations.

PropTypeDefault
orientation`"vertical""horizontal"
class_namestr
data_invalidstr
field.root(
    field.label("Remember me", html_for="remember"),
    switch.root(id="remember"),
    orientation="horizontal",
)

field.content

Flex column that groups control and descriptions when the label sits beside the control. Not required if you have no layout description block.

PropTypeDefault
class_namestr
field.root(
    checkbox.root(id="notifications"),
    field.content(
        field.label("Notifications", html_for="notifications"),
        field.description("Email, SMS, and push options."),
    ),
)

field.label

Label styled for both direct inputs and nested field child items.

PropTypeDefault
html_forstr
class_namestr
field.label("Email", html_for="email")

field.title

Renders a standalone title with matching label typography properties inside a field.content node block.

PropTypeDefault
class_namestr
field.content(
    field.title("Enable Touch ID"),
    field.description("Unlock your device faster."),
)

field.description

Helper text slot that automatically line-balances lengthy strings cleanly when utilized inside horizontal configurations.

PropTypeDefault
class_namestr
field.description("We never share your email with anyone.")

field.separator

Visual divider rule used to separate sections or categories inside a wrapping field.group component. Accepts optional inline children contents.

PropTypeDefault
class_namestr
field.separator("Or continue with")

field.error

Accessible error notification typography container block configured automatically with standard application state layout variables (role="alert").

PropTypeDefault
class_namestr
field.error("Invalid passcode combination provided.")