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 🙏

© 2026 – Pkg Stats / Ryan Hefner

action-compact-button

v15.0.5

Published

This is an Angular Module containing Components/Services using Material

Downloads

7

Readme

Action Compact Button Component

Overview

The action-compact-button library provides a compact version of action buttons with expand/collapse functionality. It displays buttons in a space-efficient manner, showing only icons in compact mode and expanding to show full labels when needed. The component implements Angular's ControlValueAccessor interface for seamless form integration.

Core Capabilities

🎯 Compact Action Button Interface

  • Space-Efficient Design: Displays buttons in compact mode (icons only) or expanded mode (with labels)
  • Expandable Interface: Toggle between compact and expanded views dynamically
  • Material Design Integration: Uses Angular Material components for consistent styling
  • Form Control Support: Implements ControlValueAccessor for reactive forms
  • Badge Support: Maintains notification badge functionality in both modes
  • Responsive Behavior: Adapts to available screen space

🔧 Features

Expand/Collapse Toggle - Dynamic view switching between compact and expanded
ControlValueAccessor Implementation - Works with Angular forms
Material Design Integration - Uses Angular Material components
Badge Notifications - Visual notification indicators in both modes
Icon-Only Display - Compact mode shows only icons to save space
Label Display - Expanded mode shows both icons and labels
State Management - Disabled states and conditional rendering
Responsive Design - Adapts to different screen sizes

Key Benefits

| Feature | Description | |---------|-------------| | Space Optimization | Compact mode saves horizontal space | | Flexible Display | Toggle between icon-only and labeled views | | Form Integration | Native Angular form control support | | Badge Support | Notification indicators work in both modes | | Consistent Styling | Material Design theming throughout |


Demo Component (ActionCompactButtonDemoComponent)

The demo component showcases the expand/collapse functionality and various button configurations.

Usage

To use the demo component in your application:

<app-compact-button-actions-demo></app-compact-button-actions-demo>

The demo includes:

  • Expandable/collapsible button interface
  • Phone button (disabled state)
  • Messages button (with badge showing 6 notifications)
  • Alerts button (zero badge state)
  • Material checkbox to control expansion state
  • Different color configurations

Summary

The action-compact-button library provides a space-efficient, expandable action button component that dynamically switches between compact (icon-only) and expanded (icon+label) display modes.


Quick Start Guide

Installation & Setup (2 minutes)

1. Import Module

// app.module.ts
import { ActionCompactButtonModule } from 'action-compact-button';

@NgModule({
  imports: [
    ActionCompactButtonModule
  ]
})
export class AppModule { }

2. No Module Configuration Required

The ActionCompactButtonModule does not require global configuration. Components can be used immediately after module import.

Quick Examples

Example 1: Basic Compact/Expand Buttons

import { Component } from '@angular/core';
import { ButtonAction } from 'action-compact-button';

@Component({
  selector: 'app-compact-buttons',
  template: `
    <div class="button-container">
      <app-compact-button-actions
        [data]="buttonActions"
        [expand]="isExpanded">
      </app-compact-button-actions>
      
      <button (click)="toggleExpansion()">
        {{ isExpanded ? 'Compact' : 'Expand' }} View
      </button>
    </div>
  `
})
export class CompactButtonsComponent {
  isExpanded = false;

  buttonActions: ButtonAction[] = [
    { icon: 'dialpad', label: 'Phone', disabled: true },
    { icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },
    { icon: 'notifications_off', label: 'Alerts', badge: 0 }
  ];

  toggleExpansion() {
    this.isExpanded = !this.isExpanded;
  }
}

Example 2: Form Control Integration

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ButtonAction } from 'action-compact-button';

@Component({
  selector: 'app-form-compact-buttons',
  template: `
    <app-compact-button-actions
      [formControl]="compactControl"
      [data]="buttonActions"
      [expand]="isExpanded">
    </app-compact-button-actions>
    
    <div class="controls">
      <label>
        <input type="checkbox" [(ngModel)]="isExpanded">
        Expand Buttons
      </label>
    </div>
    
    <div>Selected: {{ compactControl.value | json }}</div>
  `
})
export class FormCompactButtonsComponent {
  isExpanded = true;
  compactControl = new FormControl();
  
  buttonActions: ButtonAction[] = [
    { icon: 'edit', label: 'Edit', color: 'primary' },
    { icon: 'delete', label: 'Delete', color: 'warn' },
    { icon: 'share', label: 'Share', color: 'accent' }
  ];
}

Example 3: Responsive Button Panel

import { Component } from '@angular/core';
import { ButtonAction } from 'action-compact-button';

@Component({
  selector: 'app-responsive-buttons',
  template: `
    <div class="responsive-container">
      <h3>Action Panel</h3>
      
      <app-compact-button-actions
        [data]="actionButtons"
        [expand]="isExpanded"
        [disabled]="isDisabled">
      </app-compact-button-actions>
      
      <div class="controls">
        <button (click)="toggleExpanded()">
          {{ isExpanded ? 'Show Compact' : 'Show Labels' }}
        </button>
        
        <button (click)="toggleDisabled()">
          {{ isDisabled ? 'Enable' : 'Disable' }}
        </button>
      </div>
      
      <div class="status">
        Mode: {{ isExpanded ? 'Expanded' : 'Compact' }} | 
        State: {{ isDisabled ? 'Disabled' : 'Enabled' }}
      </div>
    </div>
  `,
  styles: [`
    .responsive-container { 
      padding: 1rem; 
      border: 1px solid #ddd; 
      border-radius: 4px; 
    }
    .controls { 
      margin-top: 1rem; 
      display: flex; 
      gap: 0.5rem; 
    }
    .status { 
      margin-top: 0.5rem; 
      font-size: 0.9rem; 
      color: #666; 
    }
  `]
})
export class ResponsiveButtonsComponent {
  isExpanded = false;
  isDisabled = false;

  actionButtons: ButtonAction[] = [
    { icon: 'save', label: 'Save', color: 'primary' },
    { icon: 'cancel', label: 'Cancel', color: 'warn' },
    { icon: 'help', label: 'Help', badge: 3 }
  ];

  toggleExpanded() {
    this.isExpanded = !this.isExpanded;
  }

  toggleDisabled() {
    this.isDisabled = !this.isDisabled;
  }
}

Example 4: Dashboard Action Buttons

import { Component } from '@angular/core';
import { ButtonAction } from 'action-compact-button';

@Component({
  selector: 'app-dashboard-actions',
  template: `
    <div class="dashboard">
      <div class="header">
        <h2>Dashboard</h2>
        <app-compact-button-actions
          [data]="dashboardActions"
          [expand]="showLabels"
          (selectionChange)="handleAction($event)">
        </app-compact-button-actions>
      </div>
      
      <div class="content">
        <p>Dashboard content goes here...</p>
      </div>
    </div>
  `,
  styles: [`
    .dashboard { padding: 1rem; }
    .header { 
      display: flex; 
      justify-content: space-between; 
      align-items: center; 
      margin-bottom: 2rem; 
    }
    .header h2 { margin: 0; }
  `]
})
export class DashboardActionsComponent {
  showLabels = false;

  dashboardActions: ButtonAction[] = [
    { icon: 'refresh', label: 'Refresh', color: 'primary' },
    { icon: 'settings', label: 'Settings', color: 'accent' },
    { icon: 'notifications', label: 'Notifications', badge: this.getNotificationCount() },
    { icon: 'help', label: 'Help', color: 'warn' }
  ];

  getNotificationCount(): number {
    // Logic to get notification count
    return 7;
  }

  handleAction(action: ButtonAction) {
    console.log('Action triggered:', action);
    // Handle different actions based on icon/label
    switch (action.icon) {
      case 'refresh':
        this.refreshDashboard();
        break;
      case 'settings':
        this.openSettings();
        break;
      case 'notifications':
        this.showNotifications();
        break;
      case 'help':
        this.showHelp();
        break;
    }
  }

  private refreshDashboard() {
    console.log('Refreshing dashboard...');
  }

  private openSettings() {
    console.log('Opening settings...');
  }

  private showNotifications() {
    console.log('Showing notifications...');
  }

  private showHelp() {
    console.log('Showing help...');
  }
}

Component API

Inputs

| Input | Type | Description | Default | | :--- | :--- | :--- | :--- | | data | ButtonAction[] | Array of button action configurations | [] | | expand | boolean \| string | Controls expansion state (true/expanded, false/compact) | false | | disabled | boolean | Whether the entire component is disabled | false |

Outputs

| Output | Type | Description | | :--- | :--- | :--- | | selectionChange | EventEmitter<any> | Emits when a button is selected/clicked |


Model Structures

ButtonAction Interface (Shared)

The action-compact-button package uses the same ButtonAction model as action-buttons:

export interface ButtonActionInterface {
  label?: string;        // Button text label
  icon?: string;         // Material icon name or custom icon
  disabled?: boolean;    // Individual button disabled state
  badge?: number;        // Notification badge count (0 or positive number)
  color?: string;        // Custom color (CSS color value)
  svg?: boolean;         // Whether icon is SVG format
}

ButtonAction Class (Shared)

export class ButtonAction implements ButtonActionInterface {
  constructor(
    public label?: string,
    public icon?: string,
    public disabled?: boolean = false,
    public badge?: number = 0,
    public color?: string,
    public svg?: boolean = false
  ) {}

  static adapt(data?: any): ButtonAction {
    return new ButtonAction(
      data?.label,
      data?.icon,
      (data?.disabled) ? data.disabled : false,
      (data?.badge) ? data.badge : 0,
      data?.color,
      (data?.svg) ? true : false
    );
  }
}

Usage Examples

// Compact mode buttons (icons more important)
const compactButtons: ButtonAction[] = [
  { icon: 'home', label: 'Home', color: 'primary' },
  { icon: 'search', label: 'Search', color: 'accent' },
  { icon: 'notifications', label: 'Alerts', badge: 5 },
  { icon: 'settings', label: 'Settings', color: 'warn' }
];

// Expanded mode buttons (labels more important)
const expandedButtons: ButtonAction[] = [
  { icon: 'save', label: 'Save Document', color: 'primary' },
  { icon: 'print', label: 'Print Report', color: 'accent' },
  { icon: 'email', label: 'Email Results', badge: 2 },
  { icon: 'download', label: 'Download Data', color: 'warn' }
];

// Mixed usage - some buttons work better compact, others expanded
const mixedButtons: ButtonAction[] = [
  { icon: 'home', label: 'Dashboard' },           // Good for both modes
  { icon: 'notifications', label: 'Alerts', badge: 3 },  // Badge visible in both modes
  { icon: 'settings', label: 'Settings' },        // Settings icon is descriptive
  { icon: 'book', label: 'Documentation' }        // Book icon needs label in compact mode
];

Module Configuration

ActionCompactButtonModule

No Global Configuration Required

The ActionCompactButtonModule does not provide a forRoot() method or global configuration options. All configuration is done at the component level through input properties.

Module Structure

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    MatIconModule,
    MatButtonModule,
    MatBadgeModule,
  ],
  declarations: [
    ActionCompactButtonComponent,
    ActionCompactButtonDemoComponent,
  ],
  exports:[
    ActionCompactButtonComponent,
    ActionCompactButtonDemoComponent,
  ]
})
export class ActionCompactButtonModule { }

Dependencies

  • @angular/common: Core Angular functionality
  • @angular/forms: Form control integration
  • @angular/material: Material Design components
    • MatIconModule: Icon display
    • MatButtonModule: Button base component
    • MatBadgeModule: Badge notifications
  • Shared Models: Uses ButtonAction model from action-buttons package

Styling and Customization

CSS Classes and Styling

The component uses Material Design styling and can be customized using:

  1. Global Material Theme: Configure colors in your Angular Material theme
  2. Component-specific Styles: Add custom CSS classes for different display modes
  3. Responsive Breakpoints: Customize when to show compact vs expanded mode
  4. Color Input: Use the color property for individual button styling

Example Customization

// Custom styles for compact button actions
:host ::ng-deep .compact-button-actions {
  &.compact-mode {
    .mat-button-wrapper {
      padding: 8px; // Smaller padding in compact mode
    }
    
    .button-label {
      display: none; // Hide labels in compact mode
    }
  }
  
  &.expanded-mode {
    .mat-button-wrapper {
      padding: 12px 16px; // Larger padding in expanded mode
    }
    
    .button-label {
      display: inline-block;
      margin-left: 8px;
      font-size: 0.875rem;
    }
  }
  
  // Animation for expand/collapse transition
  .mat-button {
    transition: all 0.3s ease;
  }
}

Responsive Behavior

// Auto-expand on desktop, compact on mobile
:host ::ng-deep .compact-button-actions {
  @media (min-width: 768px) {
    &[expand="false"] {
      // Force expanded mode on larger screens
      .button-label {
        display: inline-block !important;
      }
    }
  }
  
  @media (max-width: 767px) {
    // Compact mode on mobile
    &[expand="false"] {
      .button-label {
        display: none;
      }
    }
  }
}

Accessibility

ARIA Support

  • Buttons include proper ARIA labels in both compact and expanded modes
  • Keyboard navigation is supported across all button states
  • Screen reader friendly with appropriate labels and descriptions
  • Badge notifications include appropriate ARIA live regions
  • Expand/collapse state is communicated to assistive technologies

Best Practices

  1. Provide meaningful labels for all buttons (used in expanded mode)
  2. Use descriptive icons that work well in compact mode
  3. Set badge counts appropriately for notification indicators
  4. Consider screen size when implementing expand/collapse logic
  5. Test with screen readers in both compact and expanded modes
  6. Maintain consistent spacing between compact and expanded layouts

Integration Examples

With Screen Observer

import { Component } from '@angular/core';
import { ScreenObserverService } from 'screen-observer';

@Component({
  template: `
    <app-compact-button-actions
      [data]="actionButtons"
      [expand]="shouldExpand">
    </app-compact-button-actions>
  `
})
export class ResponsiveActionsComponent {
  shouldExpand = false;

  constructor(private screenObserver: ScreenObserverService) {
    this.screenObserver.screenSize$.subscribe(screenType => {
      // Expand on tablets and desktop, compact on mobile
      this.shouldExpand = ['TC52', 'Mobile'].indexOf(screenType) === -1;
    });
  }

  actionButtons: ButtonAction[] = [
    { icon: 'home', label: 'Home' },
    { icon: 'search', label: 'Search' },
    { icon: 'notifications', label: 'Alerts', badge: 3 }
  ];
}

With State Management

// Integration with HTTP Request Manager
@Component({
  template: `
    <app-compact-button-actions
      [data]="actionButtons$ | async"
      [expand]="uiState.expanded"
      (selectionChange)="handleAction($event)">
    </app-compact-button-actions>
  `
})
export class StateManagedCompactButtonsComponent {
  actionButtons$ = this.actionStore.buttons$;
  uiState = { expanded: false };
  
  constructor(private actionStore: ActionStore) {}
  
  handleAction(action: ButtonAction) {
    this.actionStore.executeAction(action);
  }
}

With Column Fitter

import { Component } from '@angular/core';
import { ColumnFitterService } from 'column-fitter';

@Component({
  template: `
    <div [style.gridTemplateColumns]="columnTemplate">
      <app-compact-button-actions
        [data]="actionButtons"
        [expand]="columnsFit > 2">
      </app-compact-button-actions>
    </div>
  `
})
export class AdaptiveActionsComponent {
  columnsFit = 1;
  columnTemplate = '1fr';

  constructor(private columnFitter: ColumnFitterService) {
    this.columnFitter.columns$.subscribe(columns => {
      this.columnsFit = columns;
      this.columnTemplate = `repeat(${columns}, 1fr)`;
    });
  }

  actionButtons: ButtonAction[] = [
    { icon: 'add', label: 'Add Item' },
    { icon: 'edit', label: 'Edit' },
    { icon: 'delete', label: 'Delete' },
    { icon: 'share', label: 'Share' }
  ];
}

Testing

Unit Testing Example

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActionCompactButtonComponent } from './action-compact-button.component';
import { ButtonAction } from './models';

describe('ActionCompactButtonComponent', () => {
  let component: ActionCompactButtonComponent;
  let fixture: ComponentFixture<ActionCompactButtonComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ ActionCompactButtonComponent ]
    }).compileComponents();

    fixture = TestBed.createComponent(ActionCompactButtonComponent);
    component = fixture.componentInstance;
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should display buttons in compact mode when expand is false', () => {
    component.data = [{ label: 'Test', icon: 'home' }];
    component.expand = false;
    fixture.detectChanges();
    
    const compiled = fixture.nativeElement;
    const labels = compiled.querySelectorAll('.button-label');
    expect(labels.length).toBe(0); // Labels hidden in compact mode
  });

  it('should display buttons in expanded mode when expand is true', () => {
    component.data = [{ label: 'Test', icon: 'home' }];
    component.expand = true;
    fixture.detectChanges();
    
    const compiled = fixture.nativeElement;
    const labels = compiled.querySelectorAll('.button-label');
    expect(labels.length).toBe(1); // Labels shown in expanded mode
  });

  it('should toggle expand state correctly', () => {
    component.data = [{ label: 'Test', icon: 'home' }];
    
    component.expand = false;
    fixture.detectChanges();
    expect(component.expand).toBe(false);
    
    component.expand = true;
    fixture.detectChanges();
    expect(component.expand).toBe(true);
  });

  it('should emit selection change when button is clicked', () => {
    spyOn(component.selectionChange, 'emit');
    component.data = [{ label: 'Test', icon: 'home' }];
    fixture.detectChanges();
    
    const button = fixture.nativeElement.querySelector('button');
    button.click();
    
    expect(component.selectionChange.emit).toHaveBeenCalled();
  });
});

Troubleshooting

Common Issues

  1. Icons not displaying: Ensure Material Icons are loaded in your index.html
  2. Labels not showing in expanded mode: Check that expand input is set to true
  3. Compact mode not working: Verify expand input is set to false or not provided
  4. Form control not working: Verify ReactiveFormsModule is imported
  5. Badge not showing: Make sure MatBadgeModule is imported in your module

Performance Tips

  1. Use OnPush change detection for better performance with large button arrays
  2. Implement trackBy for dynamic button lists
  3. Avoid frequent data object recreation to prevent unnecessary re-renders
  4. Use immutable data patterns for button action updates
  5. Consider debouncing expand/collapse state changes for smooth animations

Debug Mode

// Add debugging to track expand/collapse state
@Component({
  template: `
    <div class="debug-info">
      Expand State: {{ expand }} | 
      Data Length: {{ data?.length || 0 }} | 
      Disabled: {{ disabled }}
    </div>
    
    <app-compact-button-actions
      [data]="data"
      [expand]="expand"
      [disabled]="disabled">
    </app-compact-button-actions>
  `
})
export class DebugCompactButtonsComponent {
  expand = false;
  disabled = false;
  data: ButtonAction[] = [];
}