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> <Input placeholder="Evil Rabbit" required=true> "Name on Card" </Input> </Field> <Field> <Input placeholder="1234 5678 9012 3456" inputmode="numeric" required=true > "Card Number" </Input> <FieldDescription> "Enter your 16-digit card number" </FieldDescription> </Field> <FieldGroup class="grid grid-cols-3"> <Field> <FieldLabel>"Month"</FieldLabel> <Select placeholder="MM"> <SelectContent> <SelectItem value="01">"01"</SelectItem> <SelectItem value="02">"02"</SelectItem> <SelectItem value="03">"03"</SelectItem> <SelectItem value="04">"04"</SelectItem> <SelectItem value="05">"05"</SelectItem> <SelectItem value="06">"06"</SelectItem> <SelectItem value="07">"07"</SelectItem> <SelectItem value="08">"08"</SelectItem> <SelectItem value="09">"09"</SelectItem> <SelectItem value="10">"10"</SelectItem> <SelectItem value="11">"11"</SelectItem> <SelectItem value="12">"12"</SelectItem> </SelectContent> </Select> </Field> <Field> <FieldLabel>"Year"</FieldLabel> <Select placeholder="YYYY"> <SelectContent> <SelectItem value="2024">"2024"</SelectItem> <SelectItem value="2025">"2025"</SelectItem> <SelectItem value="2026">"2026"</SelectItem> <SelectItem value="2027">"2027"</SelectItem> <SelectItem value="2028">"2028"</SelectItem> <SelectItem value="2029">"2029"</SelectItem> </SelectContent> </Select> </Field> <Field> <Input inputmode="numeric" placeholder="123" required=true> "CVV" </Input> </Field> </FieldGroup> </FieldGroup> </FieldSet> <FieldSeparator /> <FieldSet> <FieldLegend>"Billing Address"</FieldLegend> <FieldDescription> "The billing address associated with your payment method" </FieldDescription> <Field orientation="horizontal"> <Checkbox class="font-normal" checked=true> "Same as shipping address" </Checkbox> </Field> </FieldSet> <FieldSet> <Field> <Textarea placeholder="Add any additional comments" class="resize-none"> "Comments" </Textarea> </Field> </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! { <div class="w-full max-w-md"> <FieldSet> <FieldGroup> <Field> <Input placeholder="Max Leiter">"Username"</Input> <FieldDescription> "Choose a unique username for your account." </FieldDescription> </Field> <Field> <FieldLabel>"Password"</FieldLabel> <FieldDescription>"Must be at least 8 characters long."</FieldDescription> <Input input_type="password" placeholder="••••••••" /> </Field> </FieldGroup> </FieldSet> </div> } }
Textarea
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldTextareaExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <FieldSet> <FieldGroup> <Field> <Textarea placeholder="Your feedback helps us improve..." rows=4> "Feedback" </Textarea> <FieldDescription> "Share your thoughts about our service." </FieldDescription> </Field> </FieldGroup> </FieldSet> </div> } }
Select
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSelectExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <FieldSet> <FieldGroup> <Field> <FieldLabel>"Department"</FieldLabel> <Select placeholder="Choose department"> <SelectContent> <SelectItem value="engineering">"Engineering"</SelectItem> <SelectItem value="design">"Design"</SelectItem> <SelectItem value="marketing">"Marketing"</SelectItem> <SelectItem value="sales">"Sales"</SelectItem> <SelectItem value="support">"Customer Support"</SelectItem> <SelectItem value="hr">"Human Resources"</SelectItem> <SelectItem value="finance">"Finance"</SelectItem> <SelectItem value="operations">"Operations"</SelectItem> </SelectContent> </Select> <FieldDescription> "Select your department or area of work." </FieldDescription> </Field> </FieldGroup> </FieldSet> </div> } }
Slider
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSliderExample() -> impl IntoView { let value = RwSignal::new(0.); view! { <div class="w-full max-w-md"> <FieldSet> <FieldGroup> <Field> <FieldLabel>"Price Range"</FieldLabel> <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> </FieldGroup> </FieldSet> </div> } }
Fieldset
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSetExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <FieldSet> <FieldLegend>"Address Information"</FieldLegend> <FieldDescription>"We need your address to deliver your order."</FieldDescription> <FieldGroup> <Field> <Input placeholder="123 Main St">"Street Address"</Input> </Field> <FieldGroup class="grid grid-cols-2"> <Field> <Input placeholder="Torrance">"City"</Input> </Field> <Field> <Input placeholder="90502">"Postal Code"</Input> </Field> </FieldGroup> </FieldGroup> </FieldSet> </div> } }
Checkbox
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldCheckboxExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <FieldGroup> <FieldSet> <FieldLegend variant="label">"Show these items on the desktop"</FieldLegend> <FieldDescription> "Select the items you want to show on the desktop." </FieldDescription> <FieldGroup> <CheckboxGroup> <Field orientation="horizontal"> <Checkbox class="font-normal">"Hard disks"</Checkbox> </Field> <Field orientation="horizontal"> <Checkbox class="font-normal">"External disks"</Checkbox> </Field> <Field orientation="horizontal"> <Checkbox class="font-normal">"CDs, DVDs, and iPods"</Checkbox> </Field> <Field orientation="horizontal"> <Checkbox class="font-normal">"Connected servers"</Checkbox> </Field> </CheckboxGroup> </FieldGroup> </FieldSet> <FieldSeparator /> <Field orientation="horizontal"> <Checkbox checked=true /> <FieldLabel> <FieldContent> <FieldTitle>"Sync Desktop & Documents folders"</FieldTitle> <FieldDescription> "Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other devices." </FieldDescription> </FieldContent> </FieldLabel> </Field> </FieldGroup> </div> } }
Radio
Yearly and lifetime plans offer significant savings.
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldRadioExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <FieldSet> <FieldTitle>"Subscription Plan"</FieldTitle> <FieldDescription> "Yearly and lifetime plans offer significant savings." </FieldDescription> <FieldGroup> <RadioGroup default="monthly"> <Field orientation="horizontal"> <Radio class="font-normal" value="monthly"> "Monthly ($9.99/month)" </Radio> </Field> <Field orientation="horizontal"> <Radio class="font-normal" value="yearly"> "Yearly ($99.99/year)" </Radio> </Field> <Field orientation="horizontal"> <Radio class="font-normal" value="lifetime"> "Lifetime ($299.99)" </Radio> </Field> </RadioGroup> </FieldGroup> </FieldSet> </div> } }
Switch
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldSwitchExample() -> impl IntoView { view! { <div class="w-full max-w-md"> <FieldSet> <FieldGroup> <Field orientation="horizontal"> <FieldLabel> <FieldContent> <FieldTitle>"Multi-factor authentication"</FieldTitle> <FieldDescription> "Enable multi-factor authentication. If you do not have a two-factor device, you can use a one-time code sent to your email." </FieldDescription> </FieldContent> </FieldLabel> <Switch /> </Field> </FieldGroup> </FieldSet> </div> } }
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! { <div class="w-full max-w-md"> <FieldSet> <FieldLegend variant="label">"Compute Environment"</FieldLegend> <FieldDescription> "Select the compute environment for your cluster." </FieldDescription> <FieldGroup> <RadioGroup default="kubernetes"> <Field orientation="horizontal" variant="button"> <FieldLabel> <FieldContent> <FieldTitle>"Kubernetes"</FieldTitle> <FieldDescription> "Run GPU workloads on a K8s configured cluster." </FieldDescription> </FieldContent> </FieldLabel> <Radio value="kubernetes" /> </Field> <Field orientation="horizontal" variant="button"> <FieldLabel> <FieldContent> <FieldTitle>"Virtual Machine"</FieldTitle> <FieldDescription> "Access a VM configured cluster to run GPU workloads." </FieldDescription> </FieldContent> </FieldLabel> <Radio value="vm" /> </Field> </RadioGroup> </FieldGroup> </FieldSet> </div> } }
Field Group
Stack Field components with FieldGroup. Add FieldSeparator 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! { <div class="w-full max-w-md"> <FieldGroup> <FieldSet class="gap-3"> <FieldLegend variant="label">"Responses"</FieldLegend> <FieldDescription> "Get notified when ChatGPT responds to requests that take time, like research or image generation." </FieldDescription> <Field orientation="horizontal"> <Checkbox checked=true class="font-normal" disabled=true> "Push notifications" </Checkbox> </Field> </FieldSet> <FieldSeparator /> <FieldSet> <FieldLegend variant="label">"Tasks"</FieldLegend> <FieldDescription> "Get notified when tasks you've created have updates. " <a href="#">"Manage tasks"</a> </FieldDescription> <FieldGroup> <CheckboxGroup> <Field orientation="horizontal"> <Checkbox class="font-normal">"Push notifications"</Checkbox> </Field> <Field orientation="horizontal"> <Checkbox class="font-normal">"Email notifications"</Checkbox> </Field> </CheckboxGroup> </FieldGroup> </FieldSet> </FieldGroup> </div> } }
Responsive Layout
use leptos::prelude::*; use singlestage::*; #[component] pub fn FieldResponsiveLayoutExample() -> impl IntoView { view! { <div class="w-full max-w-4xl"> <form> <FieldSet> <FieldLegend>"Profile"</FieldLegend> <FieldDescription>"Fill in your profile information."</FieldDescription> <FieldSeparator /> <FieldGroup> <Field orientation="responsive"> <FieldContent> <FieldLabel>"Name"</FieldLabel> <FieldDescription> "Provide your full name for identification" </FieldDescription> </FieldContent> <Input placeholder="Evil Rabbit" /> </Field> <FieldSeparator /> <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> <FieldSeparator /> <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 *"</FieldLabel> <Show when=move || username_invalid.get()> <FieldError>"Username is required"</FieldError> </Show> <Input invalid=username_invalid on:input=username_validate /> </Field> <Field> <FieldLabel>"Password *"</FieldLabel> <FieldError errors=password_errors /> <Input input_type="password" invalid=password_invalid on:input=password_validate /> </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 | Reactive<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 FieldGroup. Accepts optional inline content.
FieldSet
Container that renders a semantic fieldset with spacing presets.