Sections
Get Started
Components
A vertically stacked set of interactive headings that each reveal a section of content.
import { Component } from '@angular/core'
import { UbAccordionContentDirective, UbAccordionDirective, UbAccordionItemDirective, UbAccordionTriggerDirective } from '@/components/ui/accordion'
@Component({
standalone: true,
imports: [UbAccordionDirective, UbAccordionItemDirective, UbAccordionTriggerDirective, UbAccordionContentDirective],
template: `
<div ubAccordion class="w-full" orientation="vertical" type="single" collapsible defaultValue="item-1">
<div ubAccordionItem value="item-1">
<ub-accordion-trigger>Product Information</ub-accordion-trigger>
<div ubAccordionContent class="flex flex-col gap-4 text-balance">
<p>
Our flagship product combines cutting-edge technology with sleek
design. Built with premium materials, it offers unparalleled
performance and reliability.
</p>
<p>
Key features include advanced processing capabilities, and an
intuitive user interface designed for both beginners and experts.
</p>
</div>
</div>
<div ubAccordionItem value="item-2">
<ub-accordion-trigger>Shipping Details</ub-accordion-trigger>
<div ubAccordionContent class="flex flex-col gap-4 text-balance">
<p>
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express shipping
ensures delivery within 1-2 business days.
</p>
<p>
All orders are carefully packaged and fully insured. Track your
shipment in real-time through our dedicated tracking portal.
</p>
</div>
</div>
<div ubAccordionItem value="item-3">
<ub-accordion-trigger>Return Policy</ub-accordion-trigger>
<div ubAccordionContent class="flex flex-col gap-4 text-balance">
<p>
We stand behind our products with a comprehensive 30-day return
policy. If you're not completely satisfied, simply return the
item in its original condition.
</p>
<p>
Our hassle-free return process includes free return shipping and
full refunds processed within 48 hours of receiving the returned
item.
</p>
</div>
</div>
</div>
`,
})
export class AccordionDemo { }Installation
Install the following dependencies:
Copy and paste the following code into your project.
import type { ClassValue } from 'clsx'
import { Component, computed, Directive, input } from '@angular/core'
import { lucideChevronDown, NgxiLucide } from '@ngxi/lucide'
import {
RdxAccordionContentDirective,
RdxAccordionHeaderDirective,
RdxAccordionItemDirective,
RdxAccordionRootDirective,
RdxAccordionTriggerDirective,
} from '@radix-ng/primitives/accordion'
import { cn } from '@/lib/utils'
@Directive({
standalone: true,
selector: '[ubAccordion]',
hostDirectives: [
{
directive: RdxAccordionRootDirective,
inputs: ['disabled', 'orientation', 'defaultValue', 'value', 'collapsible', 'type'],
outputs: ['onValueChange'],
},
],
host: {
'data-slot': 'accordion',
},
})
export class UbAccordionDirective { }
@Directive({
standalone: true,
selector: '[ubAccordionItem]',
hostDirectives: [
{
directive: RdxAccordionItemDirective,
inputs: ['disabled', 'value'],
},
],
host: {
'[class]': 'computedClass()',
'data-slot': 'accordion-item',
},
})
export class UbAccordionItemDirective {
readonly class = input<ClassValue>()
protected readonly computedClass = computed(() => {
return cn('border-b last:border-b-0', this.class())
})
}
@Component({
standalone: true,
selector: '[ubAccordionTrigger], ub-accordion-trigger',
imports: [RdxAccordionHeaderDirective, NgxiLucide, RdxAccordionTriggerDirective],
template: `
<h3 rdxAccordionHeader class="flex">
<button [class]="computedClass()" rdxAccordionTrigger data-slot="accordion-trigger">
<ng-content></ng-content>
<svg [ngxiLucide]="lucideChevronDown" class="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200">
</svg>
</button>
</h3>
`,
})
export class UbAccordionTriggerDirective {
protected readonly lucideChevronDown = lucideChevronDown
readonly class = input<ClassValue>()
protected readonly computedClass = computed(() => {
return cn('focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180', this.class())
})
}
@Component({
standalone: true,
selector: '[ubAccordionContent], ub-accordion-content',
hostDirectives: [RdxAccordionContentDirective],
host: {
'data-slot': 'accordion-content',
'class':
'data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm',
},
template: `
<div [className]="computedClass()">
<ng-content></ng-content>
</div>
`,
})
export class UbAccordionContentDirective {
readonly class = input<ClassValue>()
protected readonly computedClass = computed(() => {
return cn('pt-0 pb-4', this.class())
})
} Expand
Update the import paths to match your project setup.
Usage
import { UbAccordion, UbAccordionContent, UbAccordionItem, UbAccordionTrigger, } from "@/components/ui/accordion"
<div ubAccordion type="single" collapsible> <div ubAccordionItem value="item-1"> <ub-accordion-trigger>Is it accessible?</ub-accordion-trigger> <div ubAccordionContent> Yes. It adheres to the WAI-ARIA design pattern. </div> </div> </div>