A vertically stacked set of interactive headings that each reveal a section of content.
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@repo/tailwindcss/ui/accordion"; const AccordionDemo = () => { return ( <Accordion collapsible class="w-full"> <AccordionItem value="item-1"> <AccordionTrigger>Is it accessible?</AccordionTrigger> <AccordionContent> Yes. It adheres to the WAI-ARIA design pattern. </AccordionContent> </AccordionItem> <AccordionItem value="item-2"> <AccordionTrigger>Is it styled?</AccordionTrigger> <AccordionContent> Yes. It comes with default styles that matches the other components' aesthetic. </AccordionContent> </AccordionItem> <AccordionItem value="item-3"> <AccordionTrigger>Is it animated?</AccordionTrigger> <AccordionContent> Yes. It's animated by default, but you can disable it if you prefer. </AccordionContent> </AccordionItem> </Accordion> ); }; export default AccordionDemo;
npx shadcn-solid@latest add accordion
npm install @kobalte/core
import { cn } from "@/libs/cn"; import type { AccordionContentProps, AccordionItemProps, AccordionTriggerProps, } from "@kobalte/core/accordion"; import { Accordion as AccordionPrimitive } from "@kobalte/core/accordion"; import type { PolymorphicProps } from "@kobalte/core/polymorphic"; import { type ParentProps, type ValidComponent, splitProps } from "solid-js"; export const Accordion = AccordionPrimitive; type accordionItemProps<T extends ValidComponent = "div"> = AccordionItemProps<T> & { class?: string; }; export const AccordionItem = <T extends ValidComponent = "div">( props: PolymorphicProps<T, accordionItemProps<T>>, ) => { const [local, rest] = splitProps(props as accordionItemProps, ["class"]); return ( <AccordionPrimitive.Item class={cn("border-b", local.class)} {...rest} /> ); }; type accordionTriggerProps<T extends ValidComponent = "button"> = ParentProps< AccordionTriggerProps<T> & { class?: string; } >; export const AccordionTrigger = <T extends ValidComponent = "button">( props: PolymorphicProps<T, accordionTriggerProps<T>>, ) => { const [local, rest] = splitProps(props as accordionTriggerProps, [ "class", "children", ]); return ( <AccordionPrimitive.Header class="flex" as="div"> <AccordionPrimitive.Trigger class={cn( "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-shadow hover:underline focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring [&[data-expanded]>svg]:rotate-180", local.class, )} {...rest} > {local.children} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-4 w-4 text-muted-foreground transition-transform duration-200" > <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m6 9l6 6l6-6" /> <title>Arrow</title> </svg> </AccordionPrimitive.Trigger> </AccordionPrimitive.Header> ); }; type accordionContentProps<T extends ValidComponent = "div"> = ParentProps< AccordionContentProps<T> & { class?: string; } >; export const AccordionContent = <T extends ValidComponent = "div">( props: PolymorphicProps<T, accordionContentProps<T>>, ) => { const [local, rest] = splitProps(props as accordionContentProps, [ "class", "children", ]); return ( <AccordionPrimitive.Content class={cn( "animate-accordion-up overflow-hidden text-sm data-[expanded]:animate-accordion-down", local.class, )} {...rest} > <div class="pb-4 pt-0">{local.children}</div> </AccordionPrimitive.Content> ); };
/** @type {import('tailwindcss').Config} */ module.exports = { theme: { extend: { keyframes: { "accordion-down": { from: { height: 0 }, to: { height: "var(--kb-accordion-content-height)" } }, "accordion-up": { from: { height: "var(--kb-accordion-content-height)" }, to: { height: 0 } } }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out" } } } };
import { cn } from "@/libs/cn"; import type { AccordionContentProps, AccordionItemProps, AccordionTriggerProps, } from "@kobalte/core/accordion"; import { Accordion as AccordionPrimitive } from "@kobalte/core/accordion"; import type { PolymorphicProps } from "@kobalte/core/polymorphic"; import { type ParentProps, type ValidComponent, splitProps } from "solid-js"; export const Accordion = AccordionPrimitive; type accordionItemProps<T extends ValidComponent = "div"> = AccordionItemProps<T> & { class?: string; }; export const AccordionItem = <T extends ValidComponent = "div">( props: PolymorphicProps<T, accordionItemProps<T>>, ) => { const [local, rest] = splitProps(props as accordionItemProps, ["class"]); return ( <AccordionPrimitive.Item class={cn("border-b", local.class)} {...rest} /> ); }; type accordionTriggerProps<T extends ValidComponent = "button"> = ParentProps< AccordionTriggerProps<T> & { class?: string; } >; export const AccordionTrigger = <T extends ValidComponent = "button">( props: PolymorphicProps<T, accordionTriggerProps<T>>, ) => { const [local, rest] = splitProps(props as accordionTriggerProps, [ "class", "children", ]); return ( <AccordionPrimitive.Header class="flex" as="div"> <AccordionPrimitive.Trigger class={cn( "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-shadow hover:underline [&[data-expanded]>svg]:rotate-180 bg-inherit focus-visible:(outline-none ring-1.5 ring-ring)", local.class, )} {...rest} > {local.children} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-4 w-4 text-muted-foreground transition-transform duration-200" > <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m6 9l6 6l6-6" /> <title>Arrow</title> </svg> </AccordionPrimitive.Trigger> </AccordionPrimitive.Header> ); }; type accordionContentProps<T extends ValidComponent = "div"> = ParentProps< AccordionContentProps<T> & { class?: string; } >; export const AccordionContent = <T extends ValidComponent = "div">( props: PolymorphicProps<T, accordionContentProps<T>>, ) => { const [local, rest] = splitProps(props as accordionContentProps, [ "class", "children", ]); return ( <AccordionPrimitive.Content class={cn( "animate-accordion-up overflow-hidden text-sm data-[expanded]:animate-accordion-down", local.class, )} {...rest} > <div class="pb-4 pt-0">{local.children}</div> </AccordionPrimitive.Content> ); };
export default defineConfig({ themes: { animation: { keyframes: { "accordion-down": "{ from { height: 0 } to { height: var(--kb-accordion-content-height) } }", "accordion-up": "{ from { height: var(--kb-accordion-content-height) } to { height: 0 } }" }, timingFns: { "accordion-down": "ease-out", "accordion-up": "ease-out" }, durations: { "accordion-down": "0.2s", "accordion-up": "0.2s" } } } });
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
<Accordion type="single" collapsible> <AccordionItem value="item-1"> <AccordionTrigger>Is it accessible?</AccordionTrigger> <AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent> </AccordionItem> </Accordion>