Field
Combine labels, controls, and help text to compose accessible form fields and grouped inputs.
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <form> <FieldGroup> <FieldSet> <FieldLegend>"Payment Method"</FieldLegend> <FieldDescription> "All transactions are secure and encrypted" </FieldDescription> <FieldGroup> <Field> <FieldLabel label_for="checkout-7j9-card-name-43j"> "Name on Card" </FieldLabel> <Input id="checkout-7j9-card-name-43j" placeholder="Evil Rabbit" /> </Field> <Field> <FieldLabel label_for="checkout-7j9-card-number-uw1"> "Card Number" </FieldLabel> <Input id="checkout-7j9-card-number-uw1" placeholder="1234 5678 9012 3456" /> <FieldDescription> "Enter your 16-digit card number" </FieldDescription> </Field> <div class="grid grid-cols-3 gap-4"> <Field> <FieldLabel label_for="checkout-exp-month-ts6"> "Month" </FieldLabel> <Select placeholder="MM" id="checkout-exp-month-ts6"> <SelectOption value="01">"01"</SelectOption> <SelectOption value="02">"02"</SelectOption> <SelectOption value="03">"03"</SelectOption> <SelectOption value="04">"04"</SelectOption> <SelectOption value="05">"05"</SelectOption> <SelectOption value="06">"06"</SelectOption> <SelectOption value="07">"07"</SelectOption> <SelectOption value="08">"08"</SelectOption> <SelectOption value="09">"09"</SelectOption> <SelectOption value="10">"10"</SelectOption> <SelectOption value="11">"11"</SelectOption> <SelectOption value="12">"12"</SelectOption> </Select> </Field> <Field> <FieldLabel label_for="checkout-7j9-exp-year-f59"> "Year" </FieldLabel> <Select id="checkout-7j9-exp-year-f59" placeholder="YYYY"> <SelectOption value="2024">"2024"</SelectOption> <SelectOption value="2025">"2025"</SelectOption> <SelectOption value="2026">"2026"</SelectOption> <SelectOption value="2027">"2027"</SelectOption> <SelectOption value="2028">"2028"</SelectOption> <SelectOption value="2029">"2029"</SelectOption> </Select> </Field> <Field> <FieldLabel label_for="checkout-7j9-cvv">"CVV"</FieldLabel> <Input id="checkout-7j9-cvv" placeholder="123" /> </Field> </div> </FieldGroup> </FieldSet> <FieldSeparator /> <FieldSet> <FieldLegend>"Billing Address"</FieldLegend> <FieldDescription> "The billing address associated with your payment method" </FieldDescription> <FieldGroup> <Field orientation="horizontal"> <Checkbox id="checkout-7j9-same-as-shipping-wgm" checked=true /> <FieldLabel label_for="checkout-7j9-same-as-shipping-wgm" class="font-normal" > "Same as shipping address" </FieldLabel> </Field> </FieldGroup> </FieldSet> <FieldSet> <FieldGroup> <Field> <FieldLabel label_for="checkout-7j9-optional-comments"> "Comments" </FieldLabel> <Textarea id="checkout-7j9-optional-comments" placeholder="Add any additional comments" class="resize-none" /> </Field> </FieldGroup> </FieldSet> <Field orientation="horizontal"> <Button button_type="submit">"Submit"</Button> <Button variant="outline" button_type="button"> "Cancel" </Button> </Field> </FieldGroup> </form> </div> } }
Input
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldInputExample() -> impl IntoView { view! { <FieldSet class="w-full max-w-xs"> <FieldGroup> <Field> <FieldLabel label_for="username">"Username"</FieldLabel> <Input id="username" input_type="text" placeholder="Max Leiter" /> <FieldDescription> "Choose a unique username for your account." </FieldDescription> </Field> <Field> <FieldLabel label_for="password">"Password"</FieldLabel> <FieldDescription>"Must be at least 8 characters long."</FieldDescription> <Input id="password" input_type="password" placeholder="••••••••" /> </Field> </FieldGroup> </FieldSet> } }
Textarea
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldTextareaExample() -> impl IntoView { view! { <FieldSet class="w-full max-w-xs"> <FieldGroup> <Field> <FieldLabel label_for="feedback">"Feedback"</FieldLabel> <Textarea id="feedback" placeholder="Your feedback helps us improve..." rows=4 /> <FieldDescription>"Share your thoughts about our service."</FieldDescription> </Field> </FieldGroup> </FieldSet> } }
Select
Select your department or area of work.
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSelectExample() -> impl IntoView { view! { <Field class="w-full max-w-xs"> <FieldLabel>"Department"</FieldLabel> <Select placeholder="Choose department"> <SelectOption value="engineering">"Engineering"</SelectOption> <SelectOption value="design">"Design"</SelectOption> <SelectOption value="marketing">"Marketing"</SelectOption> <SelectOption value="sales">"Sales"</SelectOption> <SelectOption value="support">"Customer Support"</SelectOption> <SelectOption value="hr">"Human Resources"</SelectOption> <SelectOption value="finance">"Finance"</SelectOption> <SelectOption value="operations">"Operations"</SelectOption> </Select> <FieldDescription>"Select your department or area of work."</FieldDescription> </Field> } }
Slider
Set your budget range ($0 - $0).
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSliderExample() -> impl IntoView { let value = RwSignal::new(0.); view! { <Field class="w-full max-w-xs"> <FieldTitle>"Price Range"</FieldTitle> <FieldDescription> "Set your budget range ($" <span class="font-medium tabular-nums">"0"</span> " - $" <span class="font-medium tabular-nums">{move || value.get()}</span>")." </FieldDescription> <Slider class="mt-2 w-full" max=1000. min=0. step=10. value /> </Field> } }
Fieldset
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSetExample() -> impl IntoView { view! { <FieldSet class="w-full max-w-sm"> <FieldLegend>"Address Information"</FieldLegend> <FieldDescription>"We need your address to deliver your order."</FieldDescription> <FieldGroup> <Field> <FieldLabel label_for="street">"Street Address"</FieldLabel> <Input id="street" input_type="text" placeholder="123 Main St" /> </Field> <div class="grid grid-cols-2 gap-4"> <Field> <FieldLabel label_for="city">City</FieldLabel> <Input id="city" input_type="text" placeholder="New York" /> </Field> <Field> <FieldLabel label_for="zip">Postal Code</FieldLabel> <Input id="zip" input_type="text" placeholder="90502" /> </Field> </div> </FieldGroup> </FieldSet> } }
Checkbox
Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other devices.
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldCheckboxExample() -> impl IntoView { view! { <FieldGroup class="w-full max-w-xs"> <FieldSet> <FieldLegend variant="label">"Show these items on the desktop"</FieldLegend> <FieldDescription> "Select the items you want to show on the desktop." </FieldDescription> <FieldGroup class="gap-3"> <Field orientation="horizontal"> <Checkbox id="finder-pref-9k2-hard-disks-ljj" checked=true /> <FieldLabel label_for="finder-pref-9k2-hard-disks-ljj" class="font-normal"> "Hard disks" </FieldLabel> </Field> <Field orientation="horizontal"> <Checkbox id="finder-pref-9k2-external-disks-1yg" /> <FieldLabel label_for="finder-pref-9k2-external-disks-1yg" class="font-normal" > "External disks" </FieldLabel> </Field> <Field orientation="horizontal"> <Checkbox id="finder-pref-9k2-cds-dvds-fzt" /> <FieldLabel label_for="finder-pref-9k2-cds-dvds-fzt" class="font-normal"> "CDs, DVDs, and iPods" </FieldLabel> </Field> <Field orientation="horizontal"> <Checkbox id="finder-pref-9k2-connected-servers-6l2" /> <FieldLabel label_for="finder-pref-9k2-connected-servers-6l2" class="font-normal" > "Connected servers" </FieldLabel> </Field> </FieldGroup> </FieldSet> <FieldSeparator /> <Field orientation="horizontal"> <Checkbox id="finder-pref-9k2-sync-folders-nep" checked=true /> <FieldContent> <FieldLabel label_for="finder-pref-9k2-sync-folders-nep"> "Sync Desktop & Documents folders" </FieldLabel> <FieldDescription> "Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other devices." </FieldDescription> </FieldContent> </Field> </FieldGroup> } }
Radio
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldRadioExample() -> impl IntoView { view! { <FieldSet class="w-full max-w-xs"> <FieldLegend variant="label">"Subscription Plan"</FieldLegend> <FieldDescription> "Yearly and lifetime plans offer significant savings." </FieldDescription> <RadioGroup value="monthly"> <Field orientation="horizontal"> <Radio value="monthly" id="plan-monthly" /> <FieldLabel label_for="plan-monthly" class="font-normal"> "Monthly ($9.99/month)" </FieldLabel> </Field> <Field orientation="horizontal"> <Radio value="yearly" id="plan-yearly" /> <FieldLabel label_for="plan-yearly" class="font-normal"> "Yearly ($99.99/year)" </FieldLabel> </Field> <Field orientation="horizontal"> <Radio value="lifetime" id="plan-lifetime" /> <FieldLabel label_for="plan-lifetime" class="font-normal"> "Lifetime ($299.99)" </FieldLabel> </Field> </RadioGroup> </FieldSet> } }
Switch
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSwitchExample() -> impl IntoView { view! { <Field orientation="horizontal" class="w-fit"> <FieldLabel label_for="2fa">"Multi-factor authentication"</FieldLabel> <Switch id="2fa" /> </Field> } }
Choice Card
Use the button variant to create selectable field buttons. This works with Radio, Checkbox and Switch components.
Select the compute environment for your cluster.
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldChoiceCardExample() -> impl IntoView { view! { <FieldSet class="w-full max-w-xs"> <FieldLegend variant="label">"Compute Environment"</FieldLegend> <FieldDescription>"Select the compute environment for your cluster."</FieldDescription> <RadioGroup value="kubernetes"> <FieldLabel label_for="kubernetes-r2h"> <Field orientation="horizontal"> <FieldContent> <FieldTitle>"Kubernetes"</FieldTitle> <FieldDescription> "Run GPU workloads on a K8s cluster." </FieldDescription> </FieldContent> <Radio value="kubernetes" id="kubernetes-r2h" /> </Field> </FieldLabel> <FieldLabel label_for="vm-z4k"> <Field orientation="horizontal"> <FieldContent> <FieldTitle>"Virtual Machine"</FieldTitle> <FieldDescription> "Access a cluster to run GPU workloads." </FieldDescription> </FieldContent> <Radio value="vm" id="vm-z4k" /> </Field> </FieldLabel> </RadioGroup> </FieldSet> } }
Field Group
Stack Field components with FieldGroup. Add Separator to divide them.
Get notified when ChatGPT responds to requests that take time, like research or image generation.
Get notified when tasks you've created have updates. Manage tasks
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldGroupExample() -> impl IntoView { view! { <FieldGroup class="w-full max-w-xs"> <FieldSet> <FieldLabel>"Responses"</FieldLabel> <FieldDescription> "Get notified when ChatGPT responds to requests that take time, like research or image generation." </FieldDescription> <FieldGroup> <CheckboxGroup> <Field orientation="horizontal"> <Checkbox id="push" checked=true disabled=true /> <FieldLabel label_for="push" class="font-normal"> "Push notifications" </FieldLabel> </Field> </CheckboxGroup> </FieldGroup> </FieldSet> <FieldSeparator /> <FieldSet> <FieldLabel>"Tasks"</FieldLabel> <FieldDescription> "Get notified when tasks you've created have updates. " <a href="#">"Manage tasks"</a> </FieldDescription> <FieldGroup> <CheckboxGroup> <Field orientation="horizontal"> <Checkbox id="push-tasks" /> <FieldLabel label_for="push-tasks" class="font-normal"> "Push notifications" </FieldLabel> </Field> <Field orientation="horizontal"> <Checkbox id="email-tasks" /> <FieldLabel label_for="email-tasks" class="font-normal"> "Email notifications" </FieldLabel> </Field> </CheckboxGroup> </FieldGroup> </FieldSet> </FieldGroup> } }
Responsive Layout
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldResponsiveLayoutExample() -> impl IntoView { view! { <div class="w-full max-w-lg"> <form> <FieldSet> <FieldLegend>"Profile"</FieldLegend> <FieldDescription>"Fill in your profile information."</FieldDescription> <FieldGroup> <Field orientation="responsive"> <FieldContent> <FieldLabel label_for="name">"Name"</FieldLabel> <FieldDescription> "Provide your full name for identification" </FieldDescription> </FieldContent> <Input id="name" placeholder="Evil Rabbit" invalid=true /> </Field> <Field orientation="responsive"> <FieldContent> <FieldLabel>"Message"</FieldLabel> <FieldDescription> "You can write your message here. Keep it short, preferably under 100 characters." </FieldDescription> </FieldContent> <Textarea placeholder="Hello, world!" class="min-h-[100px] resize-none sm:min-w-[300px]" /> </Field> <Field orientation="responsive"> <Button button_type="submit">"Submit"</Button> <Button button_type="button" variant="outline"> "Cancel" </Button> </Field> </FieldGroup> </FieldSet> </form> </div> } }
Errors
- Password is required
- Password must be at least 8 characters long
- Password must contain a number
- Password must contain uppercase letters
- Password must contain lowercase letters
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldErrorsExample() -> impl IntoView { let username_invalid = RwSignal::new(true); let password_invalid = RwSignal::new(true); let password_errors = RwSignal::new(vec![ "Password is required".to_string(), "Password must be at least 8 characters long".to_string(), "Password must contain a number".to_string(), "Password must contain uppercase letters".to_string(), "Password must contain lowercase letters".to_string(), ]); let username_validate = move |ev| { if event_target_value(&ev).is_empty() { username_invalid.set(true) } else { username_invalid.set(false) } }; let password_validate = move |ev| { let password = event_target_value(&ev); let mut errors = vec![]; if password.is_empty() { errors.push("Password is required".to_string()); }; if password.len() < 8 { errors.push("Password must be at least 8 characters long".to_string()); }; if !password.chars().any(|char| char.is_numeric()) { errors.push("Password must contain a number".to_string()); }; if !password.chars().any(|char| char.is_uppercase()) { errors.push("Password must contain uppercase letters".to_string()); }; if !password.chars().any(|char| char.is_lowercase()) { errors.push("Password must contain lowercase letters".to_string()); }; password_invalid.set(!errors.is_empty()); password_errors.set(errors); }; view! { <div class="w-full max-w-md"> <FieldSet> <FieldGroup> <Field> <FieldLabel>"Username" <Show when=move || username_invalid.get()><span class="text-(--destructive)">" *"</span></Show></FieldLabel> <Show when=move || username_invalid.get()> <FieldError>"Username is required"</FieldError> </Show> <Input invalid=username_invalid on:input=username_validate required=true /> </Field> <Field> <FieldLabel>"Password" <Show when=move || password_invalid.get()><span class="text-(--destructive)">" *"</span></Show></FieldLabel> <FieldError errors=password_errors /> <Input input_type="password" invalid=password_invalid on:input=password_validate required=true /> </Field> </FieldGroup> </FieldSet> </div> } }
Anatomy
Import all parts and piece them together.
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldAnatomy() -> impl IntoView { view! { <FieldSet> <FieldLegend /> <FieldDescription /> <FieldGroup> <Field> <FieldLabel /> <FieldError /> <Input /> <FieldDescription /> </Field> </FieldGroup> <FieldSeparator /> <FieldGroup> <Field> <FieldLabel> <FieldContent> <FieldTitle /> <FieldDescription /> </FieldContent> </FieldLabel> <Checkbox /> </Field> </FieldGroup> </FieldSet> } }
API Reference
Field
The core wrapper for a single field. Provides orientation control, invalid state styling, and spacing.
| Name | Type | Default | Description |
|---|---|---|---|
| orientation | String | "vertical" | Sets the display orientation. Accepted values: "vertical" | "horizontal" | "responsive". |
| variant | String | "" | Sets the display variant of the Field. Accepted values: "button". |
FieldContent
Flex column that groups control and descriptions when the label sits beside the control. Not required if you have no description.
FieldDescription
Helper text slot that automatically balances long lines in horizontal layouts.
FieldError
Accessible error container that accepts children or a reactive list of errors.
| Name | Type | Default | Description |
|---|---|---|---|
| errors | Vec<String> | [] | A reactive list of errors to display. |
FieldGroup
Layout wrapper that stacks Field components and enables queries for responsive orientations.
FieldLabel
A styled label associated with the input for a Field.
| Name | Type | Default | Description |
|---|---|---|---|
| label_for | String | "" | Renamed <label> `for` attribute to avoid name collisions. |
FieldLegend
Legend element for a FieldSet. Use the label variant to align with label sizing.
| Name | Type | Default | Description |
|---|---|---|---|
| variant | String | "legend" | Set the display style of the FieldLegend. Accepted values: "label" | "legend". |
FieldSeparator
Visual divider to separate sections inside a FieldSet. Accepts optional inline content.
FieldSet
Container that renders a semantic fieldset with spacing presets.