Accordion

A vertically stacked set of interactive headings that each reveal an associated section of content.

Loading...
 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"

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