Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Form Components

Components for building forms: inputs, checkboxes, selects, and more.

Input

Text input field:

#![allow(unused)]
fn main() {
use blinc_cn::prelude::*;

input()
    .placeholder("Enter your name...")
    .value(name)
    .on_change(|value| set_name(value))
}

Input Types

#![allow(unused)]
fn main() {
// Text (default)
input().placeholder("Name")

// Email
input().input_type("email").placeholder("Email")

// Password
input().input_type("password").placeholder("Password")

// Number
input().input_type("number").placeholder("Age")

// Search
input().input_type("search").placeholder("Search...")
}

Input States

#![allow(unused)]
fn main() {
// Disabled
input().disabled(true)

// Read-only
input().readonly(true)

// With error
input().error(true)
}

Textarea

Multi-line text input:

#![allow(unused)]
fn main() {
textarea()
    .placeholder("Enter description...")
    .rows(4)
    .value(description)
    .on_change(|value| set_description(value))
}

Checkbox

#![allow(unused)]
fn main() {
checkbox()
    .checked(is_checked)
    .on_change(|checked| set_checked(checked))
    .child(label("Accept terms and conditions"))
}

Indeterminate State

#![allow(unused)]
fn main() {
checkbox()
    .checked(some_checked)
    .indeterminate(some_checked && !all_checked)
    .on_change(|checked| toggle_all(checked))
    .child(label("Select all"))
}

Switch

Toggle switch:

#![allow(unused)]
fn main() {
switch_()
    .checked(is_enabled)
    .on_change(|enabled| set_enabled(enabled))
}

With Label

#![allow(unused)]
fn main() {
div()
    .flex_row()
    .items_center()
    .gap(8.0)
    .child(switch_().checked(dark_mode).on_change(|v| set_dark_mode(v)))
    .child(label("Dark mode"))
}

Radio Group

#![allow(unused)]
fn main() {
radio_group()
    .value(selected)
    .on_change(|value| set_selected(value))
    .child(
        div().flex_col().gap(8.0)
            .child(radio_item("small").child(label("Small")))
            .child(radio_item("medium").child(label("Medium")))
            .child(radio_item("large").child(label("Large")))
    )
}

Select

Dropdown selection:

#![allow(unused)]
fn main() {
select()
    .value(selected)
    .on_change(|value| set_selected(value))
    .child(select_trigger()
        .child(select_value().placeholder("Select option...")))
    .child(select_content()
        .child(select_item("opt1").child(text("Option 1")))
        .child(select_item("opt2").child(text("Option 2")))
        .child(select_item("opt3").child(text("Option 3"))))
}

Grouped Options

#![allow(unused)]
fn main() {
select()
    .child(select_trigger().child(select_value()))
    .child(select_content()
        .child(select_group()
            .child(select_label("Fruits"))
            .child(select_item("apple").child(text("Apple")))
            .child(select_item("banana").child(text("Banana"))))
        .child(select_separator())
        .child(select_group()
            .child(select_label("Vegetables"))
            .child(select_item("carrot").child(text("Carrot")))
            .child(select_item("broccoli").child(text("Broccoli")))))
}

Combobox

Searchable select with autocomplete:

#![allow(unused)]
fn main() {
combobox()
    .value(selected)
    .on_change(|value| set_selected(value))
    .child(combobox_trigger()
        .child(combobox_input().placeholder("Search...")))
    .child(combobox_content()
        .child(combobox_empty().child(text("No results found")))
        .child(combobox_item("react").child(text("React")))
        .child(combobox_item("vue").child(text("Vue")))
        .child(combobox_item("svelte").child(text("Svelte"))))
}

Slider

Range slider:

#![allow(unused)]
fn main() {
slider()
    .value(volume)
    .min(0.0)
    .max(100.0)
    .step(1.0)
    .on_change(|value| set_volume(value))
}

Range Slider

#![allow(unused)]
fn main() {
slider()
    .value_range(min_price, max_price)
    .min(0.0)
    .max(1000.0)
    .on_change_range(|min, max| {
        set_min_price(min);
        set_max_price(max);
    })
}

Label

#![allow(unused)]
fn main() {
// Associated with input via for
label("Email").for_id("email-input")

// Direct child of input
checkbox()
    .child(label("Remember me"))
}

Form Layout Example

#![allow(unused)]
fn main() {
div()
    .flex_col()
    .gap(24.0)
    .max_w(400.0)
    // Name field
    .child(
        div().flex_col().gap(4.0)
            .child(label("Name"))
            .child(input()
                .placeholder("John Doe")
                .value(&name)
                .on_change(|v| set_name(v)))
    )
    // Email field
    .child(
        div().flex_col().gap(4.0)
            .child(label("Email"))
            .child(input()
                .input_type("email")
                .placeholder("john@example.com")
                .value(&email)
                .on_change(|v| set_email(v)))
    )
    // Country select
    .child(
        div().flex_col().gap(4.0)
            .child(label("Country"))
            .child(select()
                .value(&country)
                .on_change(|v| set_country(v))
                .child(select_trigger().child(select_value()))
                .child(select_content()
                    .child(select_item("us").child(text("United States")))
                    .child(select_item("uk").child(text("United Kingdom")))
                    .child(select_item("ca").child(text("Canada")))))
    )
    // Terms checkbox
    .child(
        checkbox()
            .checked(accepted_terms)
            .on_change(|v| set_accepted_terms(v))
            .child(label("I accept the terms and conditions"))
    )
    // Submit button
    .child(
        button("Submit")
            .full_width(true)
            .disabled(!accepted_terms)
            .on_click(|| submit_form())
    )
}

Validation

#![allow(unused)]
fn main() {
let email = use_state(String::new());
let email_error = use_derived(|| {
    if email.is_empty() {
        None
    } else if !email.contains('@') {
        Some("Invalid email address")
    } else {
        None
    }
});

div().flex_col().gap(4.0)
    .child(label("Email"))
    .child(input()
        .value(&email)
        .error(email_error.is_some())
        .on_change(|v| set_email(v)))
    .child(
        email_error.map(|err|
            text(err).size(12.0).color(Color::RED)
        )
    )
}