Tabs

Rust UI component that displays a set of layered sections of content, known as tab pages, that are displayed one at a time.

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

use crate::components::ui::tabs::{Tabs, TabsContent, TabsTrigger};

#[component]
pub fn DemoTabs() -> impl IntoView {
    view! {
        <style>
            {".tabs__item-input:checked + .tabs__item-label {
            border-color: white;
            }
            .tabs__item-input:checked + .tabs__item-label + .tabs__item-content {
            display: block;
            }
            "}
        </style>

        <Tabs>
            <TabsTrigger checked=true>Tab One</TabsTrigger>
            <TabsContent>
                <h2>Tab One Content</h2>
                <p>{RANDOM_TEXT}</p>
                <p>{RANDOM_TEXT}</p>
                <p>{RANDOM_TEXT}</p>
            </TabsContent>

            <TabsTrigger>Tab Two</TabsTrigger>
            <TabsContent>
                <h2>Tab Two Content</h2>
                <p>{RANDOM_TEXT}</p>
                <p>{RANDOM_TEXT}</p>
            </TabsContent>

            <TabsTrigger>Tab Three</TabsTrigger>
            <TabsContent>
                <h2>Tab Three Content</h2>
                <p>{RANDOM_TEXT}</p>
            </TabsContent>
        </Tabs>
    }
}

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

const RANDOM_TEXT: &str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.";

Installation

You can run either of the following commands:

# cargo install ui-cli --force
ui add demo_tabs
ui add tabs

Update the imports to match your project setup.

Copy and paste the following code into your project:

components/ui/tabs.rs

use leptos::prelude::*;
use leptos_ui::clx;
use tw_merge::*;

mod components {
    use super::*;
    clx! {Tabs, div, "flex flex-wrap"}
    clx! {TabsContent, div,
        "tabs__item-content",
        "order-last",
        "hidden w-full",
    }
}

pub use components::*;

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

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

#[component]
pub fn TabsTrigger(
    #[prop(into, optional)] class: Signal<String>,
    #[prop(into, optional)] checked: Option<bool>,
    #[prop(into, optional)] name: Option<String>,
    children: Children,
) -> impl IntoView {
    let random_id = use_random_id();

    let class_label = Memo::new(move |_| {
        tw_merge!(
            "tabs__item-label",
            "order-1",
            "font-bold cursor-pointer block p-4 mr-[0.2rem] border-b-[0.2rem] border-transparent",
            class()
        )
    });

    view! {
        <input
            class="hidden tabs__item-input"
            type="radio"
            name=name.unwrap_or("tabs".to_string())
            id=&random_id
            checked=checked
        />
        <label class=class_label for=random_id>
            {children()}
        </label>
    }
}

Update the imports to match your project setup.

Usage

use crate::components::ui::tabs::{
    Tabs,
    TabsContent,
    TabsTrigger,
};
<Tabs>
    <TabsTrigger checked=true name="tabs">"Tab 1"</TabsTrigger>
    <TabsTrigger name="tabs">"Tab 2"</TabsTrigger>
    <TabsContent>"Content for Tab 1"</TabsContent>
    <TabsContent>"Content for Tab 2"</TabsContent>
</Tabs>