Accordion
A vertically stacked set of interactive headings that each reveal an associated section of content.
import { Component } from '@angular/core';
import {
RdxAccordionContentDirective,
RdxAccordionHeaderDirective,
RdxAccordionItemDirective,
RdxAccordionRootDirective,
RdxAccordionTriggerDirective
} from '@radix-ng/primitives/accordion';
import { ChevronDown, LucideAngularModule, X } from 'lucide-angular';
@Component({
selector: 'radix-accordion-demo',
standalone: true,
imports: [
RdxAccordionRootDirective,
RdxAccordionItemDirective,
RdxAccordionHeaderDirective,
RdxAccordionTriggerDirective,
RdxAccordionContentDirective,
LucideAngularModule
],
template: `
<div class="AccordionRoot" [defaultValue]="'item-1'" rdxAccordionRoot>
<div class="AccordionItem" [value]="'item-1'" rdxAccordionItem>
<div class="AccordionHeader" rdxAccordionHeader>
<button class="AccordionTrigger" type="button" rdxAccordionTrigger>
Is it accessible?
<lucide-angular class="AccordionChevron" [img]="ChevronDownIcon" size="16" />
</button>
</div>
<div class="AccordionContent" rdxAccordionContent>
<div class="AccordionContentText">Yes. It adheres to the WAI-ARIA design pattern.</div>
</div>
</div>
<div class="AccordionItem" [value]="'item-2'" rdxAccordionItem>
<div class="AccordionHeader" rdxAccordionHeader>
<button class="AccordionTrigger" type="button" rdxAccordionTrigger>
Is it unstyled?
<lucide-angular class="AccordionChevron" [img]="ChevronDownIcon" size="16" />
</button>
</div>
<div class="AccordionContent" rdxAccordionContent>
<div class="AccordionContentText">
Yes. It's unstyled by default, giving you freedom over the look and feel.
</div>
</div>
</div>
<div class="AccordionItem" [value]="'item-3'" rdxAccordionItem>
<div class="AccordionHeader" rdxAccordionHeader>
<button class="AccordionTrigger" type="button" rdxAccordionTrigger>
Can it be animated?
<lucide-angular class="AccordionChevron" [img]="ChevronDownIcon" size="16" />
</button>
</div>
<div class="AccordionContent" rdxAccordionContent>
<div class="AccordionContentText">Yes! You can animate the Accordion with CSS or JavaScript.</div>
</div>
</div>
</div>
`,
styleUrl: 'accordion-demo.css'
})
export class AccordionDemoComponent {
readonly ChevronDownIcon = ChevronDown;
protected readonly XIcon = X;
}
/* reset */
:host {
button,
h3 {
all: unset;
}
display: contents;
}
.AccordionRoot {
border-radius: 6px;
background-color: var(--mauve-6);
box-shadow: 0 2px 10px var(--black-a4);
}
.AccordionRoot[data-orientation='vertical'] {
width: 300px;
max-width: 295px;
}
.AccordionRoot[data-orientation='horizontal'] {
height: 300px;
display: flex;
flex-direction: row;
}
.AccordionItem {
overflow: hidden;
margin-top: 1px;
}
.AccordionItem[data-orientation='horizontal'] {
display: flex;
}
.AccordionItem[data-orientation='vertical']:first-child {
margin-top: 0;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.AccordionItem[data-orientation='vertical']:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.AccordionItem[data-orientation='horizontal']:first-child {
margin-top: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.AccordionItem[data-orientation='horizontal']:last-child {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.AccordionItem:focus-within {
position: relative;
z-index: 1;
box-shadow: 0 0 0 2px var(--mauve-12);
}
.AccordionHeader {
display: flex;
}
.AccordionTrigger {
font-family: inherit;
padding: 0 20px;
height: 45px;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 15px;
line-height: 1;
color: var(--violet-11);
box-shadow: 0 1px 0 var(--mauve-6);
background-color: white;
cursor: default;
}
.AccordionTrigger[data-orientation='horizontal'] {
height: 100%;
padding: 20px;
writing-mode: vertical-rl;
}
.AccordionTrigger[data-disabled='true'] {
color: var(--gray-7);
}
.AccordionTrigger:hover {
background-color: var(--mauve-2);
}
.AccordionContent {
display: flex;
overflow: hidden;
font-size: 15px;
color: var(--mauve-11);
background-color: var(--mauve-2);
}
.AccordionContent[data-orientation='vertical'][data-state='open'] {
animation: slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1);
}
.AccordionContent[data-orientation='vertical'][data-state='closed'] {
animation: slideUp 300ms cubic-bezier(0.87, 0, 0.13, 1);
}
.AccordionContent[data-orientation='horizontal'][data-state='open'] {
animation: slideRight 300ms cubic-bezier(0.87, 0, 0.13, 1);
}
.AccordionContent[data-orientation='horizontal'][data-state='closed'] {
animation: slideLeft 300ms cubic-bezier(0.87, 0, 0.13, 1);
}
.AccordionContentText {
padding: 15px 20px;
}
.AccordionChevron {
display: flex;
color: var(--violet-10);
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
}
.AccordionTrigger[data-state='open'] > .AccordionChevron {
transform: rotate(180deg);
}
.horizontal-flex-container {
display: flex;
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes slideUp {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
@keyframes slideRight {
from {
width: 0;
}
to {
width: var(--radix-accordion-content-width);
}
}
@keyframes slideLeft {
from {
width: var(--radix-accordion-content-width);
}
to {
width: 0;
}
}
Features
- Full keyboard navigation.
- Supports horizontal/vertical orientation.
- Supports Right to Left direction.
- Can expand one or multiple items.
- Can be controlled or uncontrolled.
API Reference
Root
Prop | Default | Type |
---|---|---|
disabled | false | boolean Whether the Accordion is disabled. |
orientation | 'vertical' | RdxAccordionOrientation The orientation of the accordion. |
defaultValue | — | string | string[] The value of the item to expand when initially rendered and type is "single". Use when you do not need to control the state of the items. |
type | 'single' | RdxAccordionType Determines whether one or multiple items can be opened at the same time. |
value | — | string | string[] The controlled value of the item to expand. |
Emit | Payload |
---|---|
onValueChange |
[value: void]
Event handler called when the expanded state of an item changes and type is "multiple". |
Data Attribute | Value |
---|---|
[data-orientation] | "vertical" | "horizontal" |
Item
Contains all the parts of a collapsible section.
Prop | Default | Type |
---|---|---|
expanded | false | boolean |
value | — | string Accordion value. |
disabled | false | boolean Whether the option is disabled. |
Data Attribute | Value |
---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Header
Wraps an rdxAccordionTrigger
.
Data Attribute | Value |
---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Trigger
Toggles the collapsed state of its associated item. It should be nested inside an rdxAccordionHeader
.
Data Attribute | Value |
---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Content
Contains the collapsible content for an item.
Data Attribute | Value |
---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
CSS Variable | Description |
---|---|
--radix-accordion-content-width | The width of the content when it opens/closes |
--radix-accordion-content-height | The height of the content when it opens/closes |