Skip to content

Buttons Inputs

github-actions[bot] edited this page Jul 8, 2026 · 3 revisions

Buttons & Inputs

Blinc provides ready-to-use input widgets with built-in state management.

Buttons

Basic Button

use blinc_layout::widgets::button::{button, Button};

fn my_ui(ctx: &WindowedContext) -> impl ElementBuilder {
    // Bare auto-keyed FSM handle — one slot per source line via
    // `#[track_caller]`. For multiple instances from the same line
    // (loops, list items) use `ctx.use_fsm_keyed(key, initial)`.
    let btn_state = ctx.use_fsm(ButtonState::Idle);

    button(btn_state, "Save")
        .on_click(|_| {
            println!("Saved!");
        })
}

Styled Buttons

button(state, "Primary")
    .bg_color(Color::rgba(0.3, 0.5, 0.9, 1.0))
    .hover_color(Color::rgba(0.4, 0.6, 1.0, 1.0))
    .pressed_color(Color::rgba(0.2, 0.4, 0.8, 1.0))
    .text_color(Color::WHITE)
    .rounded(8.0)
    .p(2.0)

Custom Content Buttons

Button::with_content(state, |s| {
    div()
        .flex_row()
        .gap(8.0)
        .items_center()
        .child(svg("icons/save.svg").w(16.0).h(16.0).tint(Color::WHITE))
        .child(text("Save").color(Color::WHITE))
})
.on_click(|_| save_file())

Disabled Buttons

let state = ctx.use_fsm(ButtonState::Disabled);

button(state, "Cannot Click")
    .disabled_color(Color::rgba(0.2, 0.2, 0.25, 0.5))

Checkboxes

Basic Checkbox

use blinc_layout::widgets::checkbox::{checkbox, checkbox_state};

fn my_ui(ctx: &WindowedContext) -> impl ElementBuilder {
    let state = checkbox_state(false);  // Initially unchecked

    checkbox(&state)
        .on_change(|checked| {
            println!("Checkbox is now: {}", checked);
        })
}

Labeled Checkbox

checkbox(&state)
    .label("Remember me")
    .label_color(Color::WHITE)

Styled Checkbox

checkbox(&state)
    .check_color(Color::rgba(0.4, 0.6, 1.0, 1.0))
    .bg_color(Color::rgba(0.2, 0.2, 0.25, 1.0))
    .rounded(4.0)
    .size(20.0)

Initially Checked

let state = checkbox_state(true);  // Start checked

Text Input

Basic Text Input

use blinc_layout::widgets::text_input::{text_input, text_input_state};

fn my_ui(ctx: &WindowedContext) -> impl ElementBuilder {
    let state = text_input_state("Enter your name...");

    text_input(&state)
        .w(300.0)
        .on_change(|text| {
            println!("Input: {}", text);
        })
}

Styled Text Input

text_input(&state)
    .w(300.0)
    .rounded(8.0)
    .bg_color(Color::rgba(0.15, 0.15, 0.2, 1.0))
    .text_color(Color::WHITE)
    .placeholder_color(Color::rgba(0.5, 0.5, 0.6, 1.0))
    .focus_border_color(Color::rgba(0.4, 0.6, 1.0, 1.0))

Reading Input Value

let state = text_input_state("");

// Later, read the current value
let current_text = state.text();

OTP Input

input_otp renders linked single-character text input slots for verification codes and PINs. It keeps a joined State<String> in sync while handling focus movement across slots.

use blinc_layout::widgets::input_otp::input_otp;

fn verification_code(ctx: &WindowedContext) -> impl ElementBuilder {
    let code = ctx.use_state_keyed("otp_code", || String::new());

    input_otp(&code, 6)
        .numeric_only(true)
        .on_complete(|code| println!("complete code: {code}"))
}

Behavior

  • Typing a character advances focus to the next slot.
  • Backspace on an empty slot rewinds focus and clears the previous slot.
  • Pasting distributes characters across the remaining slots.
  • numeric_only(true) filters typed and pasted input to ASCII digits.

Options

input_otp(&code, 6)
    .numeric_only(true)
    .masked(false)
    .gap(8.0)
    .class("verification-code")

Text Area

Basic Text Area

use blinc_layout::widgets::text_area::{text_area, text_area_state};

fn my_ui(ctx: &WindowedContext) -> impl ElementBuilder {
    let state = text_area_state("Enter description...");

    text_area(&state)
        .w(400.0)
        .h(200.0)
        .on_change(|text| {
            println!("Content: {}", text);
        })
}

Styled Text Area

text_area(&state)
    .w(400.0)
    .h(200.0)
    .rounded(8.0)
    .bg_color(Color::rgba(0.15, 0.15, 0.2, 1.0))
    .text_color(Color::WHITE)
    .font_size(14.0)
    .line_height(1.5)

Code Editor

Syntax Highlighted Code

use blinc_layout::widgets::code::code;

fn my_ui() -> impl ElementBuilder {
    let source = r#"
fn main() {
    println!("Hello, Blinc!");
}
"#;

    code(source)
        .lang("rust")
        .w_full()
        .h(300.0)
        .rounded(8.0)
        .font("Fira Code")
        .size(14.0)
}

Supported Languages

  • rust, python, javascript, typescript
  • html, css, json, yaml, xml
  • sql, bash, go, java, c, cpp
  • And more...

Form Example

fn login_form(ctx: &WindowedContext) -> impl ElementBuilder {
    let email_state = text_input_state("Email address");
    let password_state = text_input_state("Password");
    let remember_state = checkbox_state(false);
    let submit_state = ctx.use_fsm(ButtonState::Idle);

    div()
        .w(400.0)
        .p(24.0)
        .rounded(16.0)
        .bg(Color::rgba(0.12, 0.12, 0.16, 1.0))
        .flex_col()
        .gap(16.0)
        // Title
        .child(
            text("Sign In")
                .size(24.0)
                .weight(FontWeight::Bold)
                .color(Color::WHITE)
        )
        // Email field
        .child(
            div()
                .flex_col()
                .gap(4.0)
                .child(label("Email").color(Color::WHITE))
                .child(
                    text_input(&email_state)
                        .w_full()
                        .rounded(8.0)
                )
        )
        // Password field
        .child(
            div()
                .flex_col()
                .gap(4.0)
                .child(label("Password").color(Color::WHITE))
                .child(
                    text_input(&password_state)
                        .w_full()
                        .rounded(8.0)
                        // Note: password masking would be a feature to add
                )
        )
        // Remember me
        .child(
            checkbox(&remember_state)
                .label("Remember me")
                .label_color(Color::WHITE)
        )
        // Submit button
        .child(
            button(submit_state, "Sign In")
                .w_full()
                .bg_color(Color::rgba(0.3, 0.5, 0.9, 1.0))
                .text_color(Color::WHITE)
                .rounded(8.0)
                .on_click(|_| {
                    println!("Form submitted!");
                })
        )
}

Widget State Types

Each widget uses a specific state type:

Widget State Type States
Button ButtonState Idle, Hovered, Pressed, Disabled
Checkbox CheckboxState UncheckedIdle, UncheckedHovered, CheckedIdle, CheckedHovered
TextInput TextFieldState Idle, Hovered, Focused, FocusedHovered, Disabled
TextArea TextFieldState Same as TextInput

Best Practices

  1. Use unique keys for state - Each widget needs its own state key.

  2. Handle validation in on_change - Validate input as users type.

  3. Provide visual feedback - Use colors to indicate focus and errors.

  4. Group related inputs - Use flex containers to organize forms.

  5. Add labels - Every input should have an associated label for accessibility.

Navigation

Getting Started

Mobile Development

Example Gallery

Web Development

Core Concepts

Animation

Components

Component Library (blinc_cn)

Widgets

Canvas Kit

Advanced

Architecture

Contributing

Clone this wiki locally