Accordion
A vertically stacked set of interactive headings that each reveal a section of content.
Yes. It adheres to the WAI-ARIA design pattern.
Yes. It comes with default styles that matches the other components' aesthetic.
Yes. It's animated by default, but you can disable it if you prefer.
import { component$ } from '@builder.io/qwik';
import { Accordion } from '~/components/ui';
export default component$(() => {
return (
<Accordion.Root class="w-full">
<Accordion.Item>
<Accordion.Trigger header="h2">Is it accessible?</Accordion.Trigger>
<Accordion.Content>
Yes. It adheres to the WAI-ARIA design pattern.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<Accordion.Trigger>Is it styled?</Accordion.Trigger>
<Accordion.Content>
Yes. It comes with default styles that matches the other components'
aesthetic.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<Accordion.Trigger>Is it animated?</Accordion.Trigger>
<Accordion.Content>
Yes. It's animated by default, but you can disable it if you prefer.
</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
});
Installation
1. Run the following cli command or copy/paste the component code into your project
qwik-ui add accordion
import { component$, Slot, type PropsOf } from '@builder.io/qwik';
import { Accordion as HeadlessAccordion } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';
import { LuChevronDown } from '@qwikest/icons/lucide';
const Root = (props: PropsOf<typeof HeadlessAccordion.Root>) => (
<HeadlessAccordion.Root {...props} accordionItemComponent={Item}>
{props.children}
</HeadlessAccordion.Root>
);
const Item = component$<PropsOf<typeof HeadlessAccordion.Item>>((props) => {
return (
<HeadlessAccordion.Item {...props} class={cn('border-b', props.class)}>
<Slot />
</HeadlessAccordion.Item>
);
});
const Trigger = component$<
PropsOf<typeof HeadlessAccordion.Trigger> & {
header?: PropsOf<typeof HeadlessAccordion.Header>['as'];
}
>(({ header = 'h3', ...props }) => {
return (
<HeadlessAccordion.Header as={header} class="flex">
<HeadlessAccordion.Trigger
{...props}
class={cn(
'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-open]>svg]:rotate-180',
props.class,
)}
>
<Slot />
<LuChevronDown class="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</HeadlessAccordion.Trigger>
</HeadlessAccordion.Header>
);
});
const Content = component$<PropsOf<typeof HeadlessAccordion.Content>>((props) => {
return (
<HeadlessAccordion.Content
{...props}
class={cn(
'overflow-hidden text-sm data-[closed]:animate-accordion-up data-[open]:animate-accordion-down',
props.class,
)}
>
<div class="pb-4 pt-0">
<Slot />
</div>
</HeadlessAccordion.Content>
);
});
export const Accordion = {
Root,
Item,
Trigger,
Content,
};
Usage
import { Accordion } from '~/components/ui';
<Accordion.Root behavior="single" collapsible class="w-full">
<Accordion.Item id="item-1">
<Accordion.Trigger>Is it accessible?</Accordion.Trigger>
<Accordion.Content>Yes. It adheres to the WAI-ARIA design pattern.</Accordion.Content>
</Accordion.Item>
</Accordion.Root>