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

@libs-ui/components-buttons-button

v0.2.357-9

Published

> Component Button đa năng với nhiều kiểu dáng, kích thước, icon và tích hợp popover/spinner.

Readme

@libs-ui/components-buttons-button

Component Button đa năng với nhiều kiểu dáng, kích thước, icon và tích hợp popover/spinner.

Giới thiệu

LibsUiComponentsButtonsButtonComponent là một Angular Standalone Component được thiết kế để hiển thị nút bấm với đầy đủ tính năng: hỗ trợ 20+ kiểu màu sắc (primary, secondary, outline, danger, link...), 4 kích thước, loading spinner tích hợp, icon trái/phải, chế độ icon-only, custom color qua buttonCustom, và tích hợp Popover. Component sử dụng Angular Signals + ChangeDetectionStrategy.OnPush để tối ưu hiệu năng.

Tính năng

  • ✅ 20+ kiểu button: primary, secondary, third, outline, danger, green, violet, link và các biến thể
  • ✅ 4 kích thước: large, medium, small, smaller
  • ✅ Loading state với spinner tích hợp (isPending)
  • ✅ Icon trái (classIconLeft), icon phải (classIconRight) hoặc icon-only (iconOnlyType)
  • ✅ Hình ảnh bên trái (imageLeft)
  • ✅ Custom color thông qua buttonCustom (khi type = 'button-custom' hoặc 'button-link-custom')
  • ✅ Tích hợp Popover (hover/click) với đầy đủ control API
  • ✅ Trạng thái disabled với ngăn pointer events tùy chọn
  • ✅ Trạng thái active (isActive)
  • ✅ Hỗ trợ Enter key trên document (isHandlerEnterDocumentClickButton)
  • ✅ Angular Signals + ChangeDetectionStrategy.OnPush
  • ✅ Standalone Component, không cần NgModule

Khi nào sử dụng

  • Khi cần nút bấm để kích hoạt hành động (submit form, mở dialog, điều hướng...)
  • Khi cần hiển thị trạng thái loading trong lúc xử lý async operation
  • Khi cần button với popover tooltip hoặc menu dropdown
  • Khi cần button chỉ có icon, không có label
  • Khi cần tùy chỉnh màu sắc button theo brand riêng của feature

Cài đặt

npm install @libs-ui/components-buttons-button

Import

import {
  LibsUiComponentsButtonsButtonComponent,
  IButton,
  TYPE_BUTTON,
  TYPE_SIZE_BUTTON,
} from '@libs-ui/components-buttons-button';

@Component({
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  // ...
})
export class YourComponent {}

Ví dụ sử dụng

Basic — Nút bấm đơn giản

<libs_ui-components-buttons-button
  label="Lưu"
  (outClick)="handlerSave($event)" />
import { Component } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  handlerSave(event: Event): void {
    event.stopPropagation();
    // xử lý lưu dữ liệu
  }
}

Button Types — Các kiểu màu sắc

<!-- Solid buttons -->
<libs_ui-components-buttons-button type="button-primary"    label="Primary"    (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-secondary"  label="Secondary"  (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-third"      label="Third"      (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-outline"    label="Outline"    (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-danger-high" label="Danger"   (outClick)="handlerDelete($event)" />
<libs_ui-components-buttons-button type="button-danger-low"  label="Cảnh báo" (outClick)="handlerWarning($event)" />
<libs_ui-components-buttons-button type="button-green"      label="Xác nhận"  (outClick)="handlerConfirm($event)" />
<libs_ui-components-buttons-button type="button-violet"     label="Violet"    (outClick)="handlerClick($event)" />

<!-- Outline variants -->
<libs_ui-components-buttons-button type="button-outline-secondary"     label="Outline Secondary" (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-outline-green"         label="Outline Green"     (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-outline-hover-danger"  label="Hover Danger"      (outClick)="handlerClick($event)" />

<!-- Link style buttons -->
<libs_ui-components-buttons-button type="button-link-primary"      label="Xem thêm"  (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button type="button-link-danger-high"  label="Xóa"       (outClick)="handlerDelete($event)" />
<libs_ui-components-buttons-button type="button-link-green"        label="Xác nhận"  (outClick)="handlerClick($event)" />

Button Sizes — Các kích thước

<libs_ui-components-buttons-button [sizeButton]="'large'"   label="Large Button"   (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button [sizeButton]="'medium'"  label="Medium Button"  (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button [sizeButton]="'small'"   label="Small Button"   (outClick)="handlerClick($event)" />
<libs_ui-components-buttons-button [sizeButton]="'smaller'" label="Smaller Button" (outClick)="handlerClick($event)" />

Loading State — Trạng thái loading

<libs_ui-components-buttons-button
  label="Lưu thông tin"
  [isPending]="isSaving()"
  (outClick)="handlerSave($event)" />
import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-form',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './form.component.html',
})
export class FormComponent {
  protected isSaving = signal(false);

  handlerSave(event: Event): void {
    event.stopPropagation();
    this.isSaving.set(true);
    // gọi API...
    // sau khi xong: this.isSaving.set(false);
  }
}

With Icons — Button kèm icon

<!-- Icon bên trái -->
<libs_ui-components-buttons-button
  label="Thêm mới"
  [classIconLeft]="'libs-ui-icon-add'"
  (outClick)="handlerAdd($event)" />

<!-- Icon bên phải -->
<libs_ui-components-buttons-button
  label="Tiếp theo"
  [classIconRight]="'libs-ui-icon-arrow-right'"
  (outClick)="handlerNext($event)" />

<!-- Cả hai icon -->
<libs_ui-components-buttons-button
  label="Tải xuống"
  [classIconLeft]="'libs-ui-icon-download-outline'"
  [classIconRight]="'libs-ui-icon-arrow-down'"
  (outClick)="handlerDownload($event)" />

<!-- Chỉ icon, không label -->
<libs_ui-components-buttons-button
  [classIconLeft]="'libs-ui-icon-arrange'"
  [iconOnlyType]="true"
  (outClick)="handlerOpenSettings($event)" />

Disabled State — Trạng thái vô hiệu hóa

<libs_ui-components-buttons-button
  label="Không thể bấm"
  [disable]="true"
  (outClick)="handlerClick($event)" />

<!-- Disable nhưng vẫn nhận pointer events (để show tooltip) -->
<libs_ui-components-buttons-button
  label="Disabled nhưng có tooltip"
  [disable]="true"
  [ignorePointerEvent]="true"
  (outClick)="handlerClick($event)" />

Custom Color — Màu tùy chỉnh

<libs_ui-components-buttons-button
  type="button-custom"
  label="Custom Brand Color"
  [buttonCustom]="customButtonConfig"
  (outClick)="handlerClick($event)" />
import { Component } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
import { IColorButton } from '@libs-ui/services-config-project';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  protected readonly customButtonConfig: IColorButton = {
    rootColor: '#6366f1',
    configStepColor: {
      background: 500,
      color: -500,
      background_hover: 600,
    },
  };

  handlerClick(event: Event): void {
    event.stopPropagation();
  }
}

With Popover — Button kèm popover/tooltip

<libs_ui-components-buttons-button
  label="Hover để xem tooltip"
  [popover]="{
    type: 'text',
    mode: 'hover',
    config: {
      content: 'Đây là tooltip giải thích chức năng',
      width: 220
    }
  }"
  (outClick)="handlerClick($event)"
  (outPopoverEvent)="handlerPopoverEvent($event)" />
import { Component } from '@angular/core';
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
import { TYPE_POPOVER_EVENT } from '@libs-ui/components-popover';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  handlerClick(event: Event): void {
    event.stopPropagation();
  }

  handlerPopoverEvent(event: TYPE_POPOVER_EVENT): void {
    event.stopPropagation?.();
    // event: 'show' | 'hide' | 'click' | 'remove'
  }
}

Image Left — Button kèm hình ảnh

<libs_ui-components-buttons-button
  label="Đăng nhập với Google"
  [imageLeft]="{ src: '/assets/icons/google.svg', classInclude: 'mr-[8px] w-[16px] h-[16px]' }"
  (outClick)="handlerLoginWithGoogle($event)" />

Active State — Trạng thái đang được chọn

<libs_ui-components-buttons-button
  type="button-outline"
  label="Tab đang chọn"
  [isActive]="true"
  (outClick)="handlerSelect($event)" />

Class Include — Thêm class tùy chỉnh

<libs_ui-components-buttons-button
  label="Button full-width"
  classInclude="w-full justify-center"
  (outClick)="handlerClick($event)" />

Enter Key Handler — Kích hoạt bằng phím Enter

<!-- Button sẽ được click khi user nhấn Enter trên document -->
<libs_ui-components-buttons-button
  label="Xác nhận"
  [isHandlerEnterDocumentClickButton]="true"
  (outClick)="handlerConfirm($event)" />

ViewChild — Truy cập Popover Control

import { Component, viewChild } from '@angular/core';
import {
  LibsUiComponentsButtonsButtonComponent,
  IPopoverFunctionControlEvent,
} from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  template: `
    <libs_ui-components-buttons-button
      #myBtn
      label="Click"
      (outFunctionsControl)="handlerFunctionsControl($event)"
      (outClick)="handlerClick($event)" />
  `,
})
export class ExampleComponent {
  private readonly myBtn = viewChild<LibsUiComponentsButtonsButtonComponent>('myBtn');

  handlerClick(event: Event): void {
    event.stopPropagation();
    // truy cập popover control qua FunctionsControl getter
    const control = this.myBtn()?.FunctionsControl;
    control?.hide?.();
  }

  handlerFunctionsControl(control: IPopoverFunctionControlEvent): void {
    // lưu control để điều khiển popover từ bên ngoài
  }
}

@Input()

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | [buttonCustom] | IColorButton | undefined | Cấu hình màu custom — bắt buộc khi type'button-custom' hoặc 'button-link-custom' | [buttonCustom]="{ rootColor: '#6366f1', configStepColor: { background: 500 } }" | | [classIconLeft] | string | '' | Class CSS của icon hiển thị bên trái label | [classIconLeft]="'libs-ui-icon-add'" | | [classIconRight] | string | '' | Class CSS của icon hiển thị bên phải label | [classIconRight]="'libs-ui-icon-arrow-right'" | | [classInclude] | string | '' | Class CSS bổ sung gắn vào phần tử button | classInclude="w-full" | | [classLabel] | string | '' | Class CSS bổ sung cho phần tử label bên trong | [classLabel]="'font-bold'" | | [disable] | boolean | false | Vô hiệu hóa button, ngăn click và áp dụng style disabled | [disable]="isFormInvalid()" | | [flagMouse] | IFlagMouse | { isMouseEnter: false, isMouseEnterContent: false, isContainerHasScroll: false } | Trạng thái con trỏ chuột từ container cha để popover hoạt động đúng khi scroll | [flagMouse]="flagMouse()" | | [iconOnlyType] | boolean | false | Chỉ hiển thị icon, ẩn hoàn toàn label | [iconOnlyType]="true" | | [ignoreFocusWhenInputTab] | boolean | undefined | Đặt tabindex="-1" để button không nhận focus khi nhấn phím Tab | [ignoreFocusWhenInputTab]="true" | | [ignorePointerEvent] | boolean | undefined | Khi disable=true, vẫn cho phép pointer events (hữu ích khi cần show tooltip khi disabled) | [ignorePointerEvent]="true" | | [ignoreSetClickWhenShowPopover] | boolean | undefined | Không set trạng thái isClick=true khi popover mở | [ignoreSetClickWhenShowPopover]="true" | | [ignoreStopPropagationEvent] | boolean | true | Khi false, gọi event.stopPropagation() bên trong handler click của button | [ignoreStopPropagationEvent]="false" | | [imageLeft] | { src: string; classInclude?: string } | undefined | Hiển thị hình ảnh bên trái label | [imageLeft]="{ src: '/assets/google.svg', classInclude: 'mr-[8px]' }" | | [isActive] | boolean | undefined | Áp dụng trạng thái active lên button (thêm attribute active) | [isActive]="isSelected()" | | [isHandlerEnterDocumentClickButton] | boolean | undefined | Lắng nghe sự kiện keyup Enter trên document và trigger click button | [isHandlerEnterDocumentClickButton]="true" | | [isPending] | boolean | undefined | Hiển thị spinner loading, tạm thời chặn click khi đang pending | [isPending]="isLoading()" | | [label] | string | ' ' | Nội dung text hiển thị trên button, hỗ trợ i18n key | label="Lưu" hoặc label="i18n_save" | | [popover] | IPopover | {} | Cấu hình popover tích hợp (type, mode, config...) | [popover]="{ type: 'text', mode: 'hover', config: { content: 'Tooltip' } }" | | [sizeButton] | TYPE_SIZE_BUTTON | 'medium' | Kích thước button: 'large', 'medium', 'small', 'smaller' | [sizeButton]="'small'" | | [styleButton] | Record<string, any> | undefined | Inline styles trực tiếp cho phần tử <button> | [styleButton]="{ minWidth: '120px' }" | | [styleIconLeft] | Record<string, any> | undefined | Inline styles cho icon bên trái | [styleIconLeft]="{ fontSize: '18px' }" | | [type] | TYPE_BUTTON | 'button-primary' | Kiểu button xác định màu sắc và style tổng thể | type="button-secondary" | | [widthLabelPopover] | number | undefined | Chiều rộng (px) của popover hiển thị khi label bị truncate | [widthLabelPopover]="200" | | [zIndex] | number | 10 | Z-index của popover tích hợp | [zIndex]="100" |

@Output()

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outClick) | Event | Phát ra khi button được click và không bị disabled/pending | handlerClick(event: Event): void { event.stopPropagation(); /* xử lý */ } | (outClick)="handlerClick($event)" | | (outFunctionsControl) | IPopoverFunctionControlEvent | Phát ra object chứa các hàm điều khiển popover (show, hide...) sau khi popover khởi tạo xong | handlerFunctionsControl(ctrl: IPopoverFunctionControlEvent): void { event.stopPropagation?.(); this.popoverControl = ctrl; } | (outFunctionsControl)="handlerFunctionsControl($event)" | | (outPopoverEvent) | TYPE_POPOVER_EVENT | Phát ra các sự kiện lifecycle của popover: 'show', 'hide', 'click', 'remove' | handlerPopoverEvent(event: TYPE_POPOVER_EVENT): void { /* xử lý */ } | (outPopoverEvent)="handlerPopoverEvent($event)" |

Public Getter (FunctionsControl)

Truy cập qua viewChild để điều khiển popover từ bên ngoài component:

private readonly buttonRef = viewChild<LibsUiComponentsButtonsButtonComponent>('buttonRef');

// Trong template:
// <libs_ui-components-buttons-button #buttonRef ... />

// Trong TS:
const control = this.buttonRef()?.FunctionsControl;
control?.hide?.();   // ẩn popover
control?.show?.();   // hiện popover

Types & Interfaces

import {
  IButton,
  TYPE_BUTTON,
  TYPE_SIZE_BUTTON,
} from '@libs-ui/components-buttons-button';

TYPE_BUTTON

export type TYPE_BUTTON =
  // Solid buttons
  | 'button-primary'           // Nút chính màu xanh lam
  | 'button-primary-revert'    // Biến thể revert của primary
  | 'button-secondary'         // Nút phụ
  | 'button-secondary-red'     // Nút phụ màu đỏ
  | 'button-secondary-green'   // Nút phụ màu xanh lá
  | 'button-third'             // Nút cấp 3 (ít nổi bật hơn)
  | 'button-outline'           // Nút viền
  | 'button-outline-secondary' // Nút viền secondary
  | 'button-outline-green'     // Nút viền xanh lá
  | 'button-outline-hover-danger' // Nút viền, hover chuyển đỏ
  | 'button-third-hover-danger'   // Nút third, hover chuyển đỏ
  | 'button-danger-high'       // Nút nguy hiểm cao (đỏ đậm)
  | 'button-danger-low'        // Nút nguy hiểm thấp (đỏ nhạt)
  | 'button-green'             // Nút xanh lá (thành công)
  | 'button-violet'            // Nút tím
  | 'button-custom'            // Màu tùy chỉnh — bắt buộc truyền [buttonCustom]
  // Link-style buttons (không có nền, dạng text link)
  | 'button-link-primary'
  | 'button-link-third'
  | 'button-link-danger-high'
  | 'button-link-danger-low'
  | 'button-link-green'
  | 'button-link-violet'
  | 'button-link-custom'       // Link màu tùy chỉnh — bắt buộc truyền [buttonCustom]
  | string;                    // Hỗ trợ type tùy chỉnh mở rộng

TYPE_SIZE_BUTTON

export type TYPE_SIZE_BUTTON = 'large' | 'medium' | 'small' | 'smaller';

IButton

Interface dùng để cấu hình button trong danh sách (ví dụ: toolbar actions, button group):

import { IButton } from '@libs-ui/components-buttons-button';
import { IColorButton } from '@libs-ui/services-config-project';
import { IPopover } from '@libs-ui/components-popover';

export interface IButton {
  key?: string;
  type?: TYPE_BUTTON;
  sizeButton?: TYPE_SIZE_BUTTON;
  iconOnlyType?: boolean;
  label?: string;
  disable?: boolean;
  classInclude?: string;
  classIconLeft?: string;
  classIconRight?: string;
  classLabel?: string;
  popover?: IPopover;
  ignoreStopPropagationEvent?: boolean;
  zIndex?: number;
  isPending?: boolean;
  action?: (data?: any) => Promise<void>;
  styleIconLeft?: Record<string, any>;
  styleButton?: Record<string, any>;
  buttonCustom?: IColorButton;
}

Ví dụ sử dụng IButton để cấu hình danh sách toolbar:

import { Component } from '@angular/core';
import {
  LibsUiComponentsButtonsButtonComponent,
  IButton,
} from '@libs-ui/components-buttons-button';

@Component({
  selector: 'app-toolbar',
  standalone: true,
  imports: [LibsUiComponentsButtonsButtonComponent],
  template: `
    @for (btn of toolbarButtons; track btn.key) {
      <libs_ui-components-buttons-button
        [type]="btn.type || 'button-primary'"
        [label]="btn.label || ''"
        [classIconLeft]="btn.classIconLeft || ''"
        [disable]="btn.disable || false"
        (outClick)="handlerToolbarAction($event, btn)" />
    }
  `,
})
export class ToolbarComponent {
  protected readonly toolbarButtons: IButton[] = [
    { key: 'save',   type: 'button-primary',  label: 'Lưu',  classIconLeft: 'libs-ui-icon-download-outline' },
    { key: 'cancel', type: 'button-secondary', label: 'Hủy' },
    { key: 'delete', type: 'button-danger-high', label: 'Xóa', classIconLeft: 'libs-ui-icon-remove' },
  ];

  handlerToolbarAction(event: Event, btn: IButton): void {
    event.stopPropagation();
    btn.action?.();
  }
}

Lưu ý quan trọng

⚠️ buttonCustom bắt buộc với custom type: Khi type="button-custom" hoặc type="button-link-custom", bắt buộc phải truyền [buttonCustom] với rootColorconfigStepColor. Thiếu config này sẽ khiến button không hiển thị màu sắc.

⚠️ ignoreStopPropagationEvent mặc định là true: Mặc định button KHÔNG gọi event.stopPropagation(). Nếu muốn chặn event lan ra container cha, set [ignoreStopPropagationEvent]="false". Trong handler (outClick) phía consumer, nên tự gọi event.stopPropagation() để chắc chắn.

⚠️ isHandlerEnterDocumentClickButton listener global: Input này đăng ký keyup listener trên toàn bộ document. Chỉ dùng cho button duy nhất trong context cần xác nhận bằng Enter (ví dụ: nút OK trong dialog confirm). Không bật đồng thời nhiều button với flag này.

⚠️ isPending chặn click: Khi isPending=true, button hiển thị spinner và tự động bỏ qua mọi sự kiện click — không cần thêm [disable].

⚠️ iconOnlyType ẩn label hoàn toàn: Khi iconOnlyType=true, label sẽ không được render dù có truyền label. Cần truyền ít nhất classIconLeft hoặc classIconRight.

⚠️ Selector dùng dấu gạch dưới: Selector chính xác là libs_ui-components-buttons-button (dấu _ sau libs), không phải libs-ui-components-buttons-button.

Unit Tests

# Chạy test cho lib này
npx nx test components-buttons-button --testFile=libs-ui/components/buttons/button/src/button.component.spec.ts

# Toàn bộ test
npx nx test components-buttons-button