Accordion Component Tutorial
A comprehensive guide to building complex forms with the ERTPL-UI Accordion component, featuring real-world examples from inventory management systems.
📦 Installation
Install the Package
npm install @vui/accordion
Import in Your Component
import { Component } from '@angular/core';
import { VuiAccordion } from '@vui/accordion';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-my-component',
standalone: true,
imports: [VuiAccordion, ReactiveFormsModule],
// ... rest of component
})
⚠️ Important: CSS Setup for Proper Styling
If the accordion's look and feel is not appearing correctly when used as an npm module, you need to import the component's CSS styles.
Method 1: Import CSS in your styles.css
/* Add to your src/styles.css file */
@import 'node_modules/@vui/accordion/accordion.tailwind.css';
Method 2: Copy Required CSS
- Open
node_modules/@vui/accordion/accordion.tailwind.css - Copy lines 1-166 (all CSS before the utilities section)
- Paste into your project's
src/styles.cssfile
Visual Features You'll Get:
- ✨ 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
🚀 Basic Usage
Simple Accordion Example
This is the basic accordion content. Click the header to expand/collapse.
<ertpl-accordion
title="Getting Started"
[initiallyExpanded]="false"
variant="default">
<ng-template #content>
<p>This is the basic accordion content. Click the header to expand/collapse.</p>
</ng-template>
</ertpl-accordion>
🔧 Real-World Example: Search Form
This example shows how to build a complex search form using the accordion component with working expand/collapse functionality.
Working Accordion Demo
<ertpl-accordion
title="Search Filters"
[initiallyExpanded]="false"
variant="default"
(accordionToggled)="onSearchToggled($event)">
<!-- Summary Template -->
<ng-template #summary>
<div class="text-xs text-gray-500">
{{ getSearchSummary() }}
</div>
</ng-template>
<ng-template #content>
<form [formGroup]="searchForm" (ngSubmit)="onSearchSubmit()" class="space-y-4">
<!-- Header with Actions -->
<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" (click)="onClearSearch()" class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200">
Clear
</button>
<button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
Search
</button>
</div>
</div>
<!-- Form Fields Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Name</label>
<input type="text" formControlName="name" placeholder="Search by name..."
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Category</label>
<select formControlName="category" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">Select category</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Status</label>
<select formControlName="status" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">Any status</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Date Range</label>
<input type="date" formControlName="date" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
</form>
</ng-template>
</ertpl-accordion>
Component TypeScript Code
@Component({
selector: 'app-search-form',
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule,
VuiAccordion
],
// template shown above
})
export class SearchFormComponent implements OnInit {
@Output() searchApplied = new EventEmitter<any>();
@Output() searchCleared = new EventEmitter<boolean>();
@Output() searchToggled = new EventEmitter<boolean>();
searchForm!: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.initializeForm();
}
private initializeForm(): void {
this.searchForm = this.fb.group({
name: [''],
category: [''],
status: [''],
date: ['']
});
}
onSearchToggled(isExpanded: boolean): void {
console.log('Accordion toggled:', isExpanded);
this.searchToggled.emit(isExpanded);
}
onSearchSubmit(): void {
const formValue = this.searchForm.value;
console.log('Search submitted:', formValue);
this.searchApplied.emit(formValue);
}
onClearSearch(): void {
this.searchForm.reset();
this.searchCleared.emit(true);
}
getSearchSummary(): string {
const values = this.searchForm.value;
const filters = Object.entries(values)
.filter(([_, value]) => value && value !== '')
.map(([key, value]) => `${key}: ${value}`);
return filters.length > 0 ? filters.join(', ') : 'No filters applied';
}
}
✨ Key Features Demonstrated
📝 Summary Template
Shows dynamic filter summary when collapsed
{{ getSearchSummary() }}
🎯 Event Handling
Track accordion state and form submissions
(accordionToggled)="onSearchToggled($event)"
🏗️ Complex Forms
Multiple form controls with validation
ReactiveFormsModule integration
📱 Responsive Design
Grid layout adapts to screen size
grid-cols-1 md:grid-cols-4
📖 API Reference
Component Properties
Inputs
| Property | Type | Default | Description |
|---|---|---|---|
| title | string | 'Accordion' | Header title text |
| initiallyExpanded | boolean | false | Whether accordion starts expanded |
| disabled | boolean | false | Disable accordion interaction |
| showIcon | boolean | true | Show/hide chevron icon |
| variant | 'default' | 'bordered' | 'filled' | 'default' | Visual styling variant |
Outputs
| Event | Type | Description |
|---|---|---|
| accordionToggled | EventEmitter<boolean> | Emitted when accordion expands/collapses |
| expanded | EventEmitter<void> | Emitted when accordion expands |
| collapsed | EventEmitter<void> | Emitted when accordion collapses |
💡 Best Practices
✅ Do
- • Use summary templates for complex forms to show filter status
- • Handle accordion toggle events for analytics or state management
- • Use overflow-visible class for dropdowns inside accordions
- • Implement clear/reset functionality for form accordions
- • Use debouncing for API calls triggered by form changes
❌ Don't
- • Put too many form fields in a single accordion (split into multiple)
- • Forget to handle form validation and submission errors
- • Use accordions for critical actions that should always be visible
- • Nest accordions inside other accordions (use tabs instead)
- • Make accordion headers too vague - be descriptive