Skip to content

Form

A comprehensive form component that provides structured layout for form fields with support for vertical/horizontal layouts, validation, field groups, and responsive multi-column layouts.

Import

rust
use gpui_component::form::{form_field, v_form, h_form, Form, FormField};

Usage

Basic Form

rust
v_form()
    .child(
        form_field()
            .label("Name")
            .child(TextInput::new(&name_input))
    )
    .child(
        form_field()
            .label("Email")
            .child(TextInput::new(&email_input))
            .required(true)
    )

Horizontal Form Layout

rust
h_form()
    .label_width(px(120.))
    .child(
        form_field()
            .label("First Name")
            .child(TextInput::new(&first_name))
    )
    .child(
        form_field()
            .label("Last Name")
            .child(TextInput::new(&last_name))
    )

Multi-Column Form

rust
v_form()
    .column(2) // Two-column layout
    .child(
        form_field()
            .label("First Name")
            .child(TextInput::new(&first_name))
    )
    .child(
        form_field()
            .label("Last Name")
            .child(TextInput::new(&last_name))
    )
    .child(
        form_field()
            .label("Bio")
            .col_span(2) // Span across both columns
            .child(TextInput::new(&bio_input))
    )

Form Container and Layout

Vertical Layout (Default)

rust
v_form()
    .gap(px(12.))
    .child(form_field().label("Name").child(input))
    .child(form_field().label("Email").child(email_input))

Horizontal Layout

rust
h_form()
    .label_width(px(100.))
    .child(form_field().label("Name").child(input))
    .child(form_field().label("Email").child(email_input))

Custom Sizing

rust
v_form()
    .large() // Large form size
    .label_text_size(rems(1.2))
    .child(form_field().label("Title").child(input))

v_form()
    .small() // Small form size
    .child(form_field().label("Code").child(input))

Form Validation

Required Fields

rust
form_field()
    .label("Email")
    .required(true) // Shows asterisk (*) next to label
    .child(TextInput::new(&email_input))

Field Descriptions

rust
form_field()
    .label("Password")
    .description("Must be at least 8 characters long")
    .child(TextInput::new(&password_input))

Dynamic Descriptions

rust
form_field()
    .label("Bio")
    .description_fn(|_, _| {
        div().child("Use at most 100 words to describe yourself.")
    })
    .child(TextInput::new(&bio_input))

Field Visibility

rust
form_field()
    .label("Admin Settings")
    .visible(user.is_admin()) // Conditionally show field
    .child(Switch::new("admin-mode"))

Submit Handling

Basic Submit Pattern

rust
struct FormView {
    name_input: Entity<InputState>,
    email_input: Entity<InputState>,
}

impl FormView {
    fn submit(&mut self, cx: &mut Context<Self>) {
        let name = self.name_input.read(cx).value();
        let email = self.email_input.read(cx).value();

        // Validate inputs
        if name.is_empty() || email.is_empty() {
            // Show validation error
            return;
        }

        // Submit form data
        self.handle_submit(name, email, cx);
    }
}

// Form with submit button
v_form()
    .child(form_field().label("Name").child(TextInput::new(&self.name_input)))
    .child(form_field().label("Email").child(TextInput::new(&self.email_input)))
    .child(
        form_field()
            .no_label_indent()
            .child(
                Button::new("submit")
                    .primary()
                    .child("Submit")
                    .on_click(cx.listener(|this, _, _, cx| this.submit(cx)))
            )
    )

Form with Action Buttons

rust
v_form()
    .child(form_field().label("Title").child(TextInput::new(&title)))
    .child(form_field().label("Content").child(TextInput::new(&content)))
    .child(
        form_field()
            .no_label_indent()
            .child(
                h_flex()
                    .gap_2()
                    .child(Button::new("save").primary().child("Save"))
                    .child(Button::new("cancel").child("Cancel"))
                    .child(Button::new("preview").outline().child("Preview"))
            )
    )

Field Groups

rust
v_form()
    .child(
        form_field()
            .label("Name")
            .child(
                h_flex()
                    .gap_2()
                    .child(div().flex_1().child(TextInput::new(&first_name)))
                    .child(div().flex_1().child(TextInput::new(&last_name)))
            )
    )
    .child(
        form_field()
            .label("Address")
            .items_start() // Align to start for multi-line content
            .child(
                v_flex()
                    .gap_2()
                    .child(TextInput::new(&street))
                    .child(
                        h_flex()
                            .gap_2()
                            .child(div().flex_1().child(TextInput::new(&city)))
                            .child(div().w(px(100.)).child(TextInput::new(&zip)))
                    )
            )
    )

Custom Field Components

rust
form_field()
    .label("Theme Color")
    .child(ColorPicker::new(&color_state).small())

form_field()
    .label("Birth Date")
    .description("We'll send you a birthday gift!")
    .child(DatePicker::new(&date_state))

form_field()
    .label("Notifications")
    .child(
        v_flex()
            .gap_2()
            .child(Switch::new("email").label("Email notifications"))
            .child(Switch::new("push").label("Push notifications"))
            .child(Switch::new("sms").label("SMS notifications"))
    )

Conditional Fields

rust
v_form()
    .child(
        form_field()
            .label("Account Type")
            .child(Dropdown::new(&account_type))
    )
    .child(
        form_field()
            .label("Company Name")
            .visible(is_business_account) // Show only for business accounts
            .child(TextInput::new(&company_name))
    )
    .child(
        form_field()
            .label("Tax ID")
            .visible(is_business_account)
            .required(is_business_account)
            .child(TextInput::new(&tax_id))
    )

Grid Layout and Positioning

Column Spanning

rust
v_form()
    .column(3) // Three-column grid
    .child(form_field().label("First").child(input1))
    .child(form_field().label("Second").child(input2))
    .child(form_field().label("Third").child(input3))
    .child(
        form_field()
            .label("Full Width")
            .col_span(3) // Spans all three columns
            .child(TextInput::new(&full_width))
    )

Column Positioning

rust
v_form()
    .column(4)
    .child(form_field().label("A").child(input_a))
    .child(form_field().label("B").child(input_b))
    .child(
        form_field()
            .label("Positioned")
            .col_start(1) // Start at column 1
            .col_span(2)  // Span 2 columns
            .child(input_positioned)
    )

Responsive Layout

rust
v_form()
    .column(if is_mobile { 1 } else { 2 })
    .child(form_field().label("Name").child(name_input))
    .child(form_field().label("Email").child(email_input))
    .child(
        form_field()
            .label("Bio")
            .when(!is_mobile, |field| field.col_span(2))
            .child(bio_input)
    )

API Reference

Form

MethodDescription
vertical()Create vertical layout form
horizontal()Create horizontal layout form
layout(Axis)Set form layout direction
label_width(Pixels)Set label width (horizontal layout)
label_text_size(Rems)Set label text size
gap(Pixels)Set gap between fields
column(u16)Set number of columns for grid layout
child(FormField)Add form field
children(iter)Add multiple form fields
large()Set large size
small()Set small size

FormField

MethodDescription
label(str)Set field label
label_fn(fn)Set dynamic label using function
description(str)Set field description
description_fn(fn)Set dynamic description
required(bool)Mark field as required
visible(bool)Set field visibility
no_label_indent()Disable label indentation
items_start()Align items to start
items_center()Align items to center
items_end()Align items to end
col_span(u16)Set column span
col_start(i16)Set starting column
col_end(i16)Set ending column
track_focus(handle)Track focus for field

Examples

User Registration Form

rust
struct RegistrationForm {
    first_name: Entity<InputState>,
    last_name: Entity<InputState>,
    email: Entity<InputState>,
    password: Entity<InputState>,
    confirm_password: Entity<InputState>,
    terms_accepted: bool,
}

impl Render for RegistrationForm {
    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        v_form()
            .large()
            .child(
                form_field()
                    .label("Personal Information")
                    .no_label_indent()
                    .child(
                        h_flex()
                            .gap_3()
                            .child(
                                div().flex_1().child(
                                    TextInput::new(&self.first_name)
                                        .placeholder("First name")
                                )
                            )
                            .child(
                                div().flex_1().child(
                                    TextInput::new(&self.last_name)
                                        .placeholder("Last name")
                                )
                            )
                    )
            )
            .child(
                form_field()
                    .label("Email")
                    .required(true)
                    .child(TextInput::new(&self.email))
            )
            .child(
                form_field()
                    .label("Password")
                    .required(true)
                    .description("Must be at least 8 characters")
                    .child(TextInput::new(&self.password))
            )
            .child(
                form_field()
                    .label("Confirm Password")
                    .required(true)
                    .child(TextInput::new(&self.confirm_password))
            )
            .child(
                form_field()
                    .no_label_indent()
                    .child(
                        Checkbox::new("terms")
                            .label("I agree to the Terms of Service")
                            .checked(self.terms_accepted)
                            .on_click(cx.listener(|this, checked, _, cx| {
                                this.terms_accepted = *checked;
                                cx.notify();
                            }))
                    )
            )
            .child(
                form_field()
                    .no_label_indent()
                    .child(
                        Button::new("register")
                            .primary()
                            .large()
                            .w_full()
                            .child("Create Account")
                    )
            )
    }
}

Settings Form with Sections

rust
v_form()
    .column(2)
    .child(
        form_field()
            .label("Profile")
            .no_label_indent()
            .col_span(2)
            .child(Divider::horizontal())
    )
    .child(
        form_field()
            .label("Display Name")
            .child(TextInput::new(&display_name))
    )
    .child(
        form_field()
            .label("Email")
            .child(TextInput::new(&email))
    )
    .child(
        form_field()
            .label("Bio")
            .col_span(2)
            .items_start()
            .child(TextInput::new(&bio))
    )
    .child(
        form_field()
            .label("Preferences")
            .no_label_indent()
            .col_span(2)
            .child(Divider::horizontal())
    )
    .child(
        form_field()
            .label("Theme")
            .child(Dropdown::new(&theme_state))
    )
    .child(
        form_field()
            .label("Language")
            .child(Dropdown::new(&language_state))
    )
    .child(
        form_field()
            .no_label_indent()
            .child(Switch::new("notifications").label("Enable notifications"))
    )
    .child(
        form_field()
            .no_label_indent()
            .child(Switch::new("marketing").label("Marketing emails"))
    )

Contact Form

rust
v_form()
    .child(
        form_field()
            .label("Contact Information")
            .child(
                h_flex()
                    .gap_2()
                    .child(
                        Dropdown::new(&prefix_state)
                            .w(px(80.))
                    )
                    .child(
                        div().flex_1().child(
                            TextInput::new(&name_input)
                                .placeholder("Your name")
                        )
                    )
            )
    )
    .child(
        form_field()
            .label("Email")
            .required(true)
            .child(TextInput::new(&email_input))
    )
    .child(
        form_field()
            .label("Subject")
            .child(Dropdown::new(&subject_state))
    )
    .child(
        form_field()
            .label("Message")
            .required(true)
            .items_start()
            .description("Please describe your inquiry in detail")
            .child(TextInput::new(&message_input))
    )
    .child(
        form_field()
            .no_label_indent()
            .child(
                h_flex()
                    .gap_2()
                    .justify_between()
                    .child(
                        Checkbox::new("copy")
                            .label("Send me a copy")
                    )
                    .child(
                        h_flex()
                            .gap_2()
                            .child(Button::new("cancel").child("Cancel"))
                            .child(Button::new("send").primary().child("Send Message"))
                    )
            )
    )

Accessibility

  • Keyboard Navigation: Full keyboard support for all form elements
  • Focus Management: Proper focus indicators and tab order
  • Screen Readers: Labels properly associated with form controls
  • Required Fields: Visual and semantic indication of required fields
  • Error States: Clear error messaging and validation feedback
  • ARIA Labels: Proper ARIA attributes for complex form structures
  • Semantic HTML: Uses appropriate form semantics for accessibility tools