13 releases

new 0.1.12 Dec 2, 2024
0.1.11 Dec 1, 2024
0.1.10 Oct 17, 2024
0.1.8 Sep 25, 2024

#744 in Web programming

Download history 159/week @ 2024-08-30 16/week @ 2024-09-06 77/week @ 2024-09-13 655/week @ 2024-09-20 109/week @ 2024-09-27 10/week @ 2024-10-04 242/week @ 2024-10-11 63/week @ 2024-10-18 2/week @ 2024-10-25 252/week @ 2024-11-29

252 downloads per month

MIT/Apache

90KB
2K SLoC

Yewlish Checkbox

crates.io docs.rs License: MIT OR Apache-2.0

Yewlish Checkbox is a customizable checkbox component for the Yew framework. It offers a flexible API to create accessible and interactive checkbox inputs, allowing developers to manage various states and behaviors seamlessly within their Yew applications.

Features

  • Multiple States: Supports checked, unchecked, and indeterminate states.
  • Accessibility: Implements ARIA attributes to ensure compliance with accessibility standards.
  • Custom Rendering: Allows rendering as different HTML elements if needed.
  • Event Handling: Provides callbacks for state changes and interactions.
  • Theming: Easily styled via CSS classes to match your application's design.

Installation

Add the crate to your Cargo.toml:

[dependencies]
yew = "^0.21"
yewlish-checkbox = "^0.1"

Usage

Basic Checkbox

Create a simple checkbox with default props.

use yew::prelude::*;
use yewlish_checkbox::{Checkbox, CheckedState};

#[function_component(App)]
fn app() -> Html {
    html! {
        <Checkbox>
          <CheckboxIndicator
            shows_when={CheckboxState::Checked}
          >
            {""}
          </CheckboxIndicator>
        </Checkbox>
    }
}

fn main() {
    yew::start_app::<App>();
}
  • The Checkbox component handles its own state internally.
  • The CheckboxIndicator displays the check mark "✔" when the checkbox is in the CheckedState::Checked state.

Controlled Checkbox

Manage the checkbox state externally using the checked and on_checked_change props.

use yew::prelude::*;
use yewlish_checkbox::*;

#[function_component(App)]
fn app() -> Html {
    let checked_state = use_state(|| CheckedState::Unchecked);

    let on_checked_change = {
        let checked_state = checked_state.clone();
        Callback::from(move |new_state: CheckedState| {
            checked_state.set(new_state);
        })
    };

    html! {
        <Checkbox
            checked={(*checked_state).clone()}
            on_checked_change={on_checked_change}
        >
            <CheckboxIndicator show_when={CheckedState::Checked}>
                {""}
            </CheckboxIndicator>
        </Checkbox>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
  • The checkbox state is stored in a UseStateHandle.
  • The on_checked_change callback updates the state when the checkbox is toggled.

Indeterminate State

Use the indeterminate state for partially selected options.

use yew::prelude::*;
use yewlish_checkbox::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <Checkbox default_checked={CheckboxState::Indeterminate}>
            <CheckboxIndicator show_when={CheckedState::Checked}>
                {""}
            </CheckboxIndicator>
            <CheckboxIndicator show_when={CheckedState::Indeterminate}>
                {""}
            </CheckboxIndicator>
        </Checkbox>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
  • Displays a minus sign "−" when in the Indeterminate state.

Custom Rendering

Customize how the checkbox is rendered using the render_as prop.

use yew::prelude::*;
use yewlish_checkbox::{Checkbox, CheckboxRenderAsProps, CheckedState};

#[function_component(App)]
fn app() -> Html {
    let render_as = Callback::from(|props: CheckboxRenderAsProps| {
        let is_checked = props.checked == CheckedState::Checked;

        html! {
            <label class={props.class.clone()}>
                <input
                    type="checkbox"
                    checked={is_checked}
                    onclick={props.toggle.clone()}
                    disabled={props.disabled}
                    required={props.required}
                    name={props.name.clone()}
                    value={props.value.clone()}
                />

                { for props.children.iter() }
            </label>
        }
    });

    html! {
        <Checkbox render_as={render_as}>
            { "Custom Checkbox" }
        </Checkbox>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
  • The checkbox is rendered as a standard HTML checkbox input.
  • You can customize the HTML structure and styling.

Styling

Apply custom styles using the class prop.

use yew::prelude::*;
use yewlish_checkbox::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <Checkbox class="custom-checkbox">
            <CheckboxIndicator
              show_when={CheckedState::Checked}
              class="custom-indicator"
            >
                {""}
            </CheckboxIndicator>
        </Checkbox>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

Define styles in your CSS:

.custom-checkbox {
    display: flex;
    align-items: center;
}

.custom-indicator {
    color: green;
}

Disabled and Read-Only Checkboxes

Disable interaction using the disabled or readonly props.

use yew::prelude::*;
use yewlish_checkbox::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <>
            <Checkbox disabled={true}>
                <CheckboxIndicator show_when={CheckedState::Checked}>
                    {"Disabled Checkbox"}
                </CheckboxIndicator>
            </Checkbox>
            <Checkbox default_checked={CheckedState::Checked} readonly={true}>
                <CheckboxIndicator show_when={CheckedState::Checked}>
                    {"Read-Only Checkbox"}
                </CheckboxIndicator>
            </Checkbox>
        </>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
  • A disabled checkbox cannot be interacted with and appears disabled.
  • A read-only checkbox displays its state but cannot be changed by the user.

Using with Forms

Integrate with forms using the name and value props.

use yew::prelude::*;
use yewlish_checkbox::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <form>
            <label for={"terms_agreement"}>
              {"I agree to the terms"}
            </label>

            <Checkbox id="terms_agreement" name="agree_terms" value="yes">
                <CheckboxIndicator show_when={CheckedState::Checked}>
                  {""}
                </CheckboxIndicator>
            </Checkbox>

            <button type="submit">{"Submit"}</button>
        </form>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

Handling State Changes

Perform actions when the checkbox state changes.

use yew::prelude::*;
use yewlish_checkbox::*;

#[function_component(App)]
fn app() -> Html {
    let on_checked_change = Callback::from(|new_state: CheckedState| {
        if new_state == CheckedState::Checked {
          log::debug!("Checkbox is checked");
        }
    });

    html! {
        // You don't need to provide a value,
        // this checkbox will still be uncontrollable
        <Checkbox on_checked_change={on_checked_change}>
            <CheckboxIndicator show_when={CheckedState::Checked}>
                {""}
            </CheckboxIndicator>
        </Checkbox>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

Accessibility

The yewlish-checkbox component is designed to satisfy the W3C ARIA accessibility pattern guide for checkboxes. It includes ARIA attributes to ensure it is accessible to all users. The role attribute is set to checkbox, and the aria-checked attribute reflects the current state ("true", "false", or "mixed").

To ensure full accessibility:

  • Use CheckboxIndicator to provide visual feedback.
  • Set the disabled and required props as needed.
  • Provide appropriate labels and descriptions.
use yew::prelude::*;
use yewlish_checkbox::*;
use yewlish_attr_passer::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <AttrPasser name="checkbox" ..attributify {
          "aria-label" => "Check me"
        }>
          <Checkbox on_checked_change={on_checked_change}>
              <CheckboxIndicator show_when={CheckedState::Checked}>
                {""}
              </CheckboxIndicator>
          </Checkbox>
        </AttrPasser>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

Checkbox Properties

Property Type Default Description
children ChildrenWithProps None Children elements, typically one or more CheckboxIndicators.
ref NodeRef None Reference to the checkbox DOM node.
id Option None The ID of the checkbox element.
class Option None CSS class for styling the checkbox.
default_checked Option Unchecked The default checked state.
checked Option None Controlled checked state.
disabled bool false Whether the checkbox is disabled.
on_checked_change Callback None Callback when the checked state changes.
required bool false Whether the checkbox is required.
name Option None The name attribute of the checkbox.
value Option None The value attribute of the checkbox.
readonly bool false Whether the checkbox is read-only.
render_as Option<Callback<CheckboxRenderAsProps, Html>> None Custom render function for the checkbox.

CheckboxIndicator Properties

Property Type Default Description
ref NodeRef None Reference to the indicator DOM node.
class Option None CSS class for styling the indicator.
children Children None Children elements to display inside the indicator.
show_when CheckedState Checked The state when the indicator is visible.
render_as Option<Callback<CheckboxIndicatorRenderAsProps, Html>> None Custom render function for the indicator.

Testing

The yewlish-checkbox crate includes a suite of tests to ensure reliability. Tests can be run using:

wasm-pack test --firefox --headless

Ensure you have wasm-pack and a compatible browser installed.

Contributing

Contributions are welcome! If you encounter any issues or have suggestions for improvements, please open an issue or submit a pull request on GitHub.

License

Yewlish Checkbox is dual-licensed under the MIT and Apache 2.0 licenses. You may choose to use either license at your option.

Acknowledgements

This project is inspired by the Radix UI library, known for its robust and accessible UI components. Special thanks to the Radix community for their excellent work and contributions, which have greatly influenced the development of Yewlish Checkbox.

Contact

For any questions or inquiries, feel free to reach out to the author:

Kirill Korotkov Email: personal.gugfug@gmail.com

Dependencies

~11–20MB
~267K SLoC