npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ertpl-ui/accordion

v1.0.13

Published

Angular Accordion Component for ERTPL UI Library

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/accordion

Peer 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 title
  • initiallyExpanded: boolean - Initial expansion state
  • variant: 'default' | 'bordered' | 'filled' - Visual style variant
  • showIcon: 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

  1. Open node_modules/@ertpl-ui/accordion/accordion.tailwind.css
  2. Copy lines 1-166 (all CSS before the utilities section)
  3. Paste into your project's src/styles.css file

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 Template

Animation System

  • CSS-based transitions for smooth performance
  • Height animation using max-height property
  • Transform-based icon rotation
  • No JavaScript animations for better performance

🌐 Accessibility Features

  • ARIA Attributes: Full aria-expanded, aria-controls support
  • 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

  1. Use trackBy functions for multiple accordions
  2. Lazy load content using *ngIf inside content template
  3. Minimize DOM updates by using OnPush change detection
  4. 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