Multi Select Tags

A multi select tags component, made with Tailwind CSS. Works seamlessly with any children component.

  • Rust UI Icons - CopyCopy Demo
use leptos::prelude::*;
use leptos_meta::Stylesheet;

use crate::components::ui::multi_select_tags::{MultiSelectTags, MultiSelectTagsSearch, TagItem};

#[component]
pub fn DemoMultiSelectTags() -> impl IntoView {
    view! {
        <Stylesheet id="multi_select_tags" href="/components/multi_select_tags.css" />

        <div class="flex flex-col gap-4 items-center">
            <MultiSelectTagsSearch />

            <MultiSelectTags>
                {TAGS.iter().map(|&tag| view! { <TagItem>{tag}</TagItem> }).collect::<Vec<_>>()}
            </MultiSelectTags>
        </div>
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                      ✨ CONSTANTS ✨                       */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

const TAGS: [&str; 15] = [
    "Docker",
    "Kubernetes",
    "AWS",
    "GraphQL",
    "MongoDB",
    "PostgreSQL",
    "Redis",
    "Git",
    "Webpack",
    "Vite",
    "Cypress",
    "Storybook",
    "Tailwind",
    "Prisma",
    "Nginx",
];

Installation

You can run either of the following commands:

# cargo install ui-cli --force
ui add demo_multi_select_tags
ui add multi_select_tags

Update the imports to match your project setup.

Copy and paste the following code into your project:

components/ui/multi_select_tags.rs

use leptos::prelude::*;
use leptos_ui::{clx, div};

use crate::components::hooks::use_random::use_random_id;

mod components {
    use super::*;
    clx! {MultiSelectTags, div, "tags flex flex-wrap gap-3 p-3 rounded-2xl border border-input w-[400px]"}
    div! {RootSearch, "search flex flex-wrap gap-3 w-[400px] min-h-[48px] p-3 border border-input rounded-lg"}
    clx! {RootItem, button, "flex items-center gap-2 p-2 rounded-lg cursor-pointer text-muted-foreground border-none"}
}

pub use components::*;

#[component]
pub fn MultiSelectTagsSearch() -> impl IntoView {
    view! {
        <RootSearch onclick="const tag = event.target.closest('button'); if (tag) { document.startViewTransition(() => { document.querySelector('.tags').appendChild(tag); }); }" />
    }
}

#[component]
pub fn TagItem(children: Children) -> impl IntoView {
    let random_id = use_random_id();

    let transition_name = format!("view-transition-name: tag-{random_id}; order: {random_id}");

    view! {
        <RootItem
            onclick="const tag = event.target.closest('button'); if (tag) { document.startViewTransition(() => { document.querySelector('.search').appendChild(tag); }); }"
            style=transition_name
        >
            {children()}
            <span class="display-none">X</span>
        </RootItem>
    }
}

Update the imports to match your project setup.

Usage

// Coming soon 🦀