This is the Accordion description
Rust/UI component that displays an Accordion.
accordion
- Copy Demo
This is the Accordion description
This is the Accordion description
use leptos::prelude::*;
use crate::components::ui::accordion::{
Accordion, AccordionContent, AccordionDescription, AccordionItem, AccordionTitle, AccordionTrigger,
};
#[component]
pub fn DemoAccordion() -> impl IntoView {
view! {
<Accordion class="max-w-[400px]">
<AccordionItem>
<AccordionTrigger open=true>
<AccordionTitle>Accordion item 01</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="pt-0">
<AccordionDescription>"This is the Accordion description"</AccordionDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger>
<AccordionTitle>Accordion item 02</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="pt-0">
<AccordionDescription>"This is the Accordion description"</AccordionDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger>
<AccordionTitle>Accordion item 03</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="pt-0">
<AccordionDescription>"This is the Accordion description"</AccordionDescription>
</AccordionContent>
</AccordionItem>
</Accordion>
}
}
Installation
You can run either of the following commands:
# cargo install ui-cli --forceui add demo_accordionui add accordion
Update the imports to match your project setup.
Copy and paste the following code into your project:
components/ui/accordion.rs
use icons::ChevronDown;
use leptos::prelude::*;
use leptos_ui::clx;
use tw_merge::*;
use crate::registry::hooks::use_random::use_random_id;
mod components {
use super::*;
clx! {Accordion, div, "divide-y divide-input w-full"}
clx! {AccordionItem, div, "w-full [&:has(>input:checked)>label>svg:last-child]:rotate-180"}
clx! {AccordionTitle, h4, "text-sm font-medium"}
clx! {AccordionHeader, div, "flex gap-2 items-center [&_svg:not([class*='size-'])]:size-4"}
clx! {RootContent, article, "grid overflow-hidden transition-all duration-400 grid-rows-[0fr] peer-checked:grid-rows-[1fr]"}
clx! {AccordionDescription, p, "text-muted-foreground text-sm"}
clx! {AccordionLink, a, "grid gap-2.5 items-center p-2 grid-cols-[auto_1fr] [&_svg:not([class*='size-'])]:size-4 hover:bg-muted"}
}
pub use components::*;
/* ========================================================== */
/* ✨ FUNCTIONS ✨ */
/* ========================================================== */
#[component]
pub fn AccordionContent(#[prop(into, optional)] class: String, children: Children) -> impl IntoView {
let merged_class = tw_merge!("p-3 pt-0", class);
view! {
<RootContent>
// * Used for the animation using grid CSS trick.
<div data-name="__AccordionContentInner" class="min-h-[0]">
<div class=merged_class>{children()}</div>
</div>
</RootContent>
}
}
/* ========================================================== */
/* ✨ FUNCTIONS ✨ */
/* ========================================================== */
#[derive(Default)]
pub enum AccordionTriggerIcon {
#[default]
ChevronDown,
Plus,
}
#[component]
pub fn AccordionTrigger(
#[prop(into, optional)] class: String,
#[prop(default = false)] open: bool,
// TODO. AccrodionTriggerIcon
children: Children,
) -> impl IntoView {
let accordion_id = use_random_id();
let label_class = tw_merge!(
"flex justify-between items-center p-3 list-none cursor-pointer [&_svg:not([class*='size-'])]:size-4 peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2",
class
);
view! {
<>
<input
id=accordion_id.clone()
type="checkbox"
class="overflow-hidden absolute p-0 -m-px w-px h-px whitespace-nowrap border-0 peer"
style="clip: rect(0, 0, 0, 0)"
checked=open
/>
<label for=accordion_id class=label_class>
{children()}
<ChevronDown class="transition-all duration-300" />
</label>
</>
}
}
Update the imports to match your project setup.
Usage
use crate::components::ui::accordion::{
Accordion,
AccordionContent,
AccordionHeader,
AccordionItem,
AccordionTitle,
};
<Accordion class="max-w-[400px]">
<AccordionItem>
<AccordionHeader>
<AccordionTitle>"Accordion Item"</AccordionTitle>
</AccordionHeader>
<AccordionContent>
"Accordion content goes here"
</AccordionContent>
</AccordionItem>
</Accordion>
Examples
Accordion Bordered
- Copy Demo
This is the Accordion description
This is the Accordion description
This is the Accordion description
use leptos::prelude::*;
use crate::components::ui::accordion::{
Accordion, AccordionContent, AccordionDescription, AccordionItem, AccordionTitle, AccordionTrigger,
};
#[component]
pub fn DemoAccordionBordered() -> impl IntoView {
view! {
<Accordion class="overflow-hidden rounded-lg border bg-background max-w-[400px]">
<AccordionItem>
<AccordionTrigger open=true class="peer-checked:bg-accent hover:bg-accent">
<AccordionTitle>Accordion item 01</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="pt-2">
<AccordionDescription>"This is the Accordion description"</AccordionDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger class="peer-checked:bg-accent hover:bg-accent">
<AccordionTitle>Accordion item 02</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="pt-2">
<AccordionDescription>"This is the Accordion description"</AccordionDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger class="peer-checked:bg-accent hover:bg-accent">
<AccordionTitle>Accordion item 03</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="pt-2">
<AccordionDescription>"This is the Accordion description"</AccordionDescription>
</AccordionContent>
</AccordionItem>
</Accordion>
}
}
Accordion with Icons
- Copy Demo
use icons::{AlignHorizontalSpaceAround, Blocks, Compass, Expand, LogIn, PanelLeft, Search};
use leptos::prelude::*;
use crate::components::ui::accordion::{
Accordion, AccordionContent, AccordionItem, AccordionLink, AccordionTitle, AccordionTrigger,
};
#[component]
pub fn DemoAccordionIcons() -> impl IntoView {
view! {
<Accordion class="overflow-hidden rounded-lg border bg-background max-w-[500px]">
<AccordionItem>
<AccordionTrigger open=true class="peer-checked:bg-accent hover:bg-accent">
<AccordionTitle>Registry</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="p-0">
<ul class="text-sm">
<li>
<AccordionLink attr:href="/docs/components">
<Blocks />
<span>Components</span>
</AccordionLink>
</li>
<li>
<AccordionLink attr:href="/docs/extensions">
<Expand />
<span>Extensions</span>
</AccordionLink>
</li>
<li>
<AccordionLink attr:href="/docs/hooks">
<Compass />
<span>Hooks</span>
</AccordionLink>
</li>
<li>
<AccordionLink attr:href="/icons">
<Search />
<span>Icons</span>
</AccordionLink>
</li>
</ul>
</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger class="peer-checked:bg-accent hover:bg-accent">
<AccordionTitle>Blocks</AccordionTitle>
</AccordionTrigger>
<AccordionContent class="p-0">
<ul class="text-sm">
<li>
<AccordionLink attr:href="/blocks/login">
<LogIn />
<span>Login</span>
</AccordionLink>
</li>
<li>
<AccordionLink attr:href="/blocks/sidenav">
<PanelLeft />
<span>Sidenav</span>
</AccordionLink>
</li>
<li>
<AccordionLink attr:href="/blocks/parallax">
<AlignHorizontalSpaceAround />
<span>Parallax</span>
</AccordionLink>
</li>
</ul>
</AccordionContent>
</AccordionItem>
<AccordionLink class="p-3" attr:href="/themes">
<AccordionTitle>Themes</AccordionTitle>
</AccordionLink>
<AccordionLink class="p-3" attr:href="/icons">
<AccordionTitle>Icons</AccordionTitle>
</AccordionLink>
</Accordion>
}
}