Docs
Accordion
Accordion
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;
Installation
npx shadcn-solid@latest add accordion
Install the following dependencies:
npm install @kobalte/core
Copy and paste the following code into your project:
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>
);
};
Update config:
/** @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"
}
}
}
};
Install the following dependencies:
npm install @kobalte/core
Copy and paste the following code into your project:
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>
);
};
Update config:
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"
}
}
}
});
Usage
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>