@ertpl-ui/accordion
v1.0.13
Published
Angular Accordion Component for ERTPL UI Library
Maintainers
Readme
@ertpl-ui/accordion
A highly flexible, template-driven Angular accordion component with customizable styling, smooth animations, and full accessibility support. Perfect for creating expandable content sections with complete control over content structure.
🚀 Features
- ✅ Template-Driven - Use ng-template for complete content control
- ✅ Summary Template - Optional collapsed state preview
- ✅ Multiple Variants - Default, bordered, and filled styles
- ✅ Smooth Animations - CSS-based expand/collapse transitions
- ✅ Accessibility - Full ARIA support and keyboard navigation
- ✅ Form Integration - Perfect for complex forms and inputs
- ✅ Event Handling - Track expand/collapse state changes
- ✅ TypeScript - Full type safety and IntelliSense support
📦 Installation
npm install @ertpl-ui/accordionPeer Dependencies
Ensure you have the following dependencies installed:
npm install @angular/core @angular/common tailwindcss🎯 Basic Usage
Simple Text Content
import { Component } from '@angular/core';
import { AccordionComponent } from '@ertpl-ui/accordion';
@Component({
standalone: true,
imports: [AccordionComponent],
template: `
<ertpl-accordion
title="Getting Started"
[initiallyExpanded]="false"
variant="default">
<ng-template #content>
<p>This is the accordion content. You can put any HTML here!</p>
</ng-template>
</ertpl-accordion>
`
})
export class MyComponent {}Advanced Form Integration
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { AccordionComponent } from '@ertpl-ui/accordion';
@Component({
standalone: true,
imports: [AccordionComponent, ReactiveFormsModule],
template: `
<ertpl-accordion
title="Search Filters"
[initiallyExpanded]="false"
variant="bordered"
(accordionToggled)="onToggle($event)">
<!-- Summary Template (shows when collapsed) -->
<ng-template #summary>
<div class="text-xs text-gray-500">
{{ getActiveFilters() }}
</div>
</ng-template>
<!-- Main Content Template -->
<ng-template #content>
<form [formGroup]="searchForm" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<input
formControlName="name"
placeholder="Search by name..."
class="px-3 py-2 border rounded-lg">
<select formControlName="category" class="px-3 py-2 border rounded-lg">
<option value="">Select category</option>
<option value="tech">Technology</option>
<option value="design">Design</option>
</select>
</div>
<button type="submit"
class="px-4 py-2 bg-blue-600 text-white rounded-lg">
Apply Filters
</button>
</form>
</ng-template>
</ertpl-accordion>
`
})
export class SearchComponent {
searchForm: FormGroup;
constructor(private fb: FormBuilder) {
this.searchForm = this.fb.group({
name: [''],
category: ['']
});
}
onToggle(expanded: boolean): void {
console.log('Accordion is now:', expanded ? 'expanded' : 'collapsed');
}
getActiveFilters(): string {
const values = this.searchForm.value;
const filters = Object.entries(values)
.filter(([_, value]) => value)
.map(([key]) => key);
return filters.length ? `Active filters: ${filters.join(', ')}` : 'No filters applied';
}
}🔧 API Reference
Component Inputs
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| title | string | '' | Accordion header title |
| initiallyExpanded | boolean | false | Whether accordion starts expanded |
| variant | 'default' \| 'bordered' \| 'filled' | 'default' | Visual style variant |
| showIcon | boolean | true | Show expand/collapse chevron icon |
Component Outputs
| Event | Type | Description |
|-------|------|-------------|
| accordionToggled | EventEmitter<boolean> | Emitted when accordion expands/collapses |
Template References
The component uses two ng-template references:
#content- Required: Main accordion content (always visible when expanded)#summary- Optional: Summary content (visible when collapsed)
🎨 Styling Variants
Default Variant
<ertpl-accordion title="Default Style" variant="default">
<ng-template #content>Content here</ng-template>
</ertpl-accordion>Bordered Variant
<ertpl-accordion title="With Border" variant="bordered">
<ng-template #content>Content with border styling</ng-template>
</ertpl-accordion>Filled Variant
<ertpl-accordion title="Filled Background" variant="filled">
<ng-template #content>Content with background fill</ng-template>
</ertpl-accordion>💡 Advanced Examples
Search Filters with Summary
<div class="h-full w-full overflow-visible p-4">
<ertpl-accordion
title="Search Filters"
[initiallyExpanded]="false"
variant="bordered"
(accordionToggled)="onToggle($event)">
<!-- Summary Template (shows when collapsed) -->
<ng-template #summary>
<div class="text-xs text-gray-500">
{{ getActiveFilters() }}
</div>
</ng-template>
<!-- Main Content Template -->
<ng-template #content>
<form [formGroup]="searchForm" class="space-y-4">
<div class="flex items-center justify-between mb-6">
<h3 class="text-lg font-medium text-gray-900">Search Form</h3>
<div class="flex items-center space-x-3">
<button type="button"
class="px-4 py-2 bg-blue-100 text-white rounded-lg">
Clear Filters
</button>
<button type="submit"
class="px-4 py-2 bg-blue-600 text-white rounded-lg">
Apply Filters
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<input
formControlName="name"
placeholder="Search by name..."
class="px-3 py-2 border rounded-lg">
<select formControlName="category" class="px-3 py-2 border rounded-lg">
<option value="">Select category</option>
<option value="tech">Technology</option>
<option value="design">Design</option>
</select>
</div>
</form>
</ng-template>
</ertpl-accordion>
</div>Filled Background Variant
<div class="h-full w-full overflow-visible p-4">
<ertpl-accordion title="Filled Background" variant="filled">
<ng-template #summary>
<div class="text-xs text-gray-500">
{{ getActiveFilters() }}
</div>
</ng-template>
<ng-template #content>Content with background fill</ng-template>
</ertpl-accordion>
</div>Bordered Variant
<div class="h-full w-full overflow-visible p-4">
<ertpl-accordion title="With Border" variant="bordered">
<ng-template #content>Content with border styling</ng-template>
</ertpl-accordion>
</div>Multiple Accordions with State Management
@Component({
template: `
<div class="space-y-4">
<ertpl-accordion
*ngFor="let section of sections; trackBy: trackSection"
[title]="section.title"
[initiallyExpanded]="section.expanded"
(accordionToggled)="updateSection(section.id, $event)">
<ng-template #content>
<div [innerHTML]="section.content"></div>
</ng-template>
</ertpl-accordion>
</div>
`
})
export class MultiAccordionComponent {
sections = [
{ id: 1, title: 'Section 1', content: '<p>Content 1</p>', expanded: false },
{ id: 2, title: 'Section 2', content: '<p>Content 2</p>', expanded: true },
];
trackSection(index: number, section: any): number {
return section.id;
}
updateSection(id: number, expanded: boolean): void {
const section = this.sections.find(s => s.id === id);
if (section) {
section.expanded = expanded;
}
}
}🔧 API Reference
Inputs
title: string- Accordion header titleinitiallyExpanded: boolean- Initial expansion statevariant: 'default' | 'bordered' | 'filled'- Visual style variantshowIcon: boolean- Show/hide chevron icon
Outputs
accordionToggled: EventEmitter<boolean>- Expansion state change event
Templates
#content(required) - Main accordion content#summary(optional) - Collapsed state summary
🎨 Custom Styling
The accordion component comes with built-in CSS styling for a polished look and feel. If you're not seeing the component styled properly when used as an npm module, follow these steps:
CSS Setup for Proper Styling
Important: If the accordion's look and feel is not appearing correctly, copy the CSS styles from accordion.tailwind.css (lines 1-166) to your main styles.css file.
Method 1: Copy Required CSS
- Open
node_modules/@ertpl-ui/accordion/accordion.tailwind.css - Copy lines 1-166 (all CSS before the utilities section)
- Paste into your project's
src/styles.cssfile
Method 2: Import the CSS File
/* In your styles.css file */
@import 'node_modules/@ertpl-ui/accordion/accordion.tailwind.css';Built-in CSS Classes
The component uses these custom CSS classes:
.ertpl-accordion- Main container styling.ertpl-accordion-header- Header button styling.ertpl-accordion-flex-container- Header layout.ertpl-accordion-title-section- Title area.ertpl-accordion-chevron- Icon styling.ertpl-accordion-content- Content area styling
Visual Features
- ✨ Rounded corners with proper border management
- 🎯 Focus states with violet ring highlighting
- 🌈 Header highlighting when expanded (light violet background)
- 🎨 Smooth transitions for all state changes
- 📱 Responsive design for mobile and desktop
Override Styles
If you need to customize the appearance:
/* Override component styles in your styles.css */
.ertpl-accordion {
border-color: #your-color !important;
background-color: #your-bg-color !important;
}
.ertpl-accordion-header {
background-color: #your-header-bg !important;
}
.ertpl-accordion-header.bg-violet-50 {
background-color: #your-expanded-color !important;
}🏗️ Architecture
Component Structure
AccordionComponent
├── Header (clickable)
│ ├── Title
│ ├── Summary Template (when collapsed)
│ └── Chevron Icon
└── Content (collapsible)
└── Content TemplateAnimation System
- CSS-based transitions for smooth performance
- Height animation using
max-heightproperty - Transform-based icon rotation
- No JavaScript animations for better performance
🌐 Accessibility Features
- ARIA Attributes: Full
aria-expanded,aria-controlssupport - Keyboard Navigation: Space/Enter to toggle, Tab to navigate
- Screen Reader Support: Proper labeling and state announcements
- Focus Management: Visible focus indicators and proper focus flow
🧪 Testing Examples
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AccordionComponent } from '@ertpl-ui/accordion';
describe('AccordionComponent', () => {
let component: AccordionComponent;
let fixture: ComponentFixture<AccordionComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AccordionComponent]
});
fixture = TestBed.createComponent(AccordionComponent);
component = fixture.componentInstance;
});
it('should toggle on click', () => {
component.title = 'Test';
fixture.detectChanges();
const header = fixture.nativeElement.querySelector('.accordion-header');
header.click();
expect(component.isExpanded).toBe(true);
});
});🚀 Performance Tips
- Use trackBy functions for multiple accordions
- Lazy load content using
*ngIfinside content template - Minimize DOM updates by using OnPush change detection
- Optimize large content with virtual scrolling if needed
🔗 Related Components
This accordion works well with other ERTPL UI components:
@ertpl-ui/text-input- For form inputs inside accordion@ertpl-ui/select- For dropdown selections@ertpl-ui/modal- For additional interaction layers
📄 License
MIT © Varun Singh
