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-tab

v0.2.357-7

Published

> Component tab dạng button, hỗ trợ nhiều màu, badge count và tuỳ biến màu riêng với type `other`.

Readme

@libs-ui/components-buttons-tab

Component tab dạng button, hỗ trợ nhiều màu, badge count và tuỳ biến màu riêng với type other.

Giới thiệu

LibsUiComponentsButtonsTabComponent là standalone Angular component hiển thị danh sách tab dưới dạng button có màu sắc phân biệt. Component hỗ trợ two-way binding cho tab đang chọn, badge count cho từng tab, disable toàn bộ hoặc từng tab riêng lẻ, và khả năng tuỳ biến màu hoàn toàn thông qua otherConfig khi type = 'other'.

Tính năng

  • ✅ Hiển thị danh sách tab với 8 màu có sẵn: blue, green, red, orange, yellow, cyan, purple, brown
  • ✅ Two-way binding key đang chọn qua [(keySelected)]
  • ✅ Badge count cho từng tab với các chế độ hiển thị (x, 0x, x+)
  • ✅ Disable toàn bộ component hoặc disable từng tab riêng lẻ
  • ✅ Tuỳ biến màu hoàn toàn (màu chữ, nền, nền badge) với type = 'other' + otherConfig
  • ✅ Tự động escape HTML trong label để tránh XSS
  • ✅ Hỗ trợ i18n qua TranslateModule
  • ✅ Hỗ trợ popover tooltip khi label bị cắt ngắn
  • ✅ Standalone Component, OnPush Change Detection, Angular Signals

Khi nào sử dụng

  • Khi cần hiển thị danh sách tab dạng button (segment navigation, bộ lọc theo nhóm)
  • Khi cần hiển thị count/badge cho từng tab (số lượng thông báo, số mục chờ xử lý)
  • Khi cần tuỳ biến màu theo theme sẵn có hoặc cấu hình màu riêng (type = 'other')
  • Khi cần disable toàn bộ hoặc disable từng tab item theo điều kiện nghiệp vụ

Cài đặt

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

Import

import {
  LibsUiComponentsButtonsTabComponent,
  IButtonTab,
  IOtherConfig,
  TYPE_BUTTON_TAB,
} from '@libs-ui/components-buttons-tab';

Ví dụ sử dụng

1. Basic — Tabs với nhiều màu

example.component.html

<libs_ui-components-buttons-tab
  [items]="items"
  [(keySelected)]="selectedKey"
  (outKeySelected)="handlerKeySelected($event)"
/>

example.component.ts

import { Component, signal } from '@angular/core';
import { LibsUiComponentsButtonsTabComponent, IButtonTab } from '@libs-ui/components-buttons-tab';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [LibsUiComponentsButtonsTabComponent],
  templateUrl: './example.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleComponent {
  protected selectedKey = model<string>('overview');

  protected readonly items: IButtonTab[] = [
    { key: 'overview', label: 'Overview', type: 'blue' },
    { key: 'details',  label: 'Details',  type: 'green' },
    { key: 'settings', label: 'Settings', type: 'orange' },
  ];

  protected handlerKeySelected(event: Event): void {
    event.stopPropagation();
    // key đã được cập nhật tự động qua two-way binding [(keySelected)]
  }
}

2. With Badge — Badge count cho từng tab

example-badge.component.html

<libs_ui-components-buttons-tab
  [items]="itemsWithBadge"
  [(keySelected)]="selectedKey"
  (outKeySelected)="handlerKeySelected($event)"
/>

example-badge.component.ts

import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { LibsUiComponentsButtonsTabComponent, IButtonTab } from '@libs-ui/components-buttons-tab';

@Component({
  selector: 'app-example-badge',
  standalone: true,
  imports: [LibsUiComponentsButtonsTabComponent],
  templateUrl: './example-badge.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleBadgeComponent {
  protected selectedKey = model<string>('inbox');

  protected readonly itemsWithBadge: IButtonTab[] = [
    { key: 'inbox',    label: 'Inbox',    type: 'blue',   count: 12,  modeCount: 'x+', maxCount: 99 },
    { key: 'mentions', label: 'Mentions', type: 'purple', count: 3,   modeCount: 'x+', maxCount: 99 },
    { key: 'requests', label: 'Requests', type: 'cyan',   count: 105, modeCount: 'x+', maxCount: 99 },
  ];

  protected handlerKeySelected(event: Event): void {
    event.stopPropagation();
  }
}

3. Disabled — Disable toàn bộ hoặc từng tab

example-disabled.component.html

<!-- Disable toàn bộ component -->
<libs_ui-components-buttons-tab
  [items]="items"
  [disable]="true"
  [(keySelected)]="selectedKey"
/>

<!-- Disable từng tab riêng lẻ qua thuộc tính disable trong IButtonTab -->
<libs_ui-components-buttons-tab
  [items]="itemsPartialDisabled"
  [(keySelected)]="selectedKey"
  (outKeySelected)="handlerKeySelected($event)"
/>

example-disabled.component.ts

import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { LibsUiComponentsButtonsTabComponent, IButtonTab } from '@libs-ui/components-buttons-tab';

@Component({
  selector: 'app-example-disabled',
  standalone: true,
  imports: [LibsUiComponentsButtonsTabComponent],
  templateUrl: './example-disabled.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleDisabledComponent {
  protected selectedKey = model<string>('a');

  protected readonly items: IButtonTab[] = [
    { key: 'a', label: 'Tab A', type: 'blue' },
    { key: 'b', label: 'Tab B', type: 'green' },
    { key: 'c', label: 'Tab C', type: 'orange' },
  ];

  protected readonly itemsPartialDisabled: IButtonTab[] = [
    { key: 'a', label: 'Tab A',           type: 'blue' },
    { key: 'b', label: 'Tab B (disabled)', type: 'red',   disable: true },
    { key: 'c', label: 'Tab C',           type: 'green' },
  ];

  protected handlerKeySelected(event: Event): void {
    event.stopPropagation();
  }
}

4. Other — Tuỳ biến màu hoàn toàn

example-other.component.html

<libs_ui-components-buttons-tab
  [items]="itemsOther"
  [otherConfig]="otherConfig"
  [(keySelected)]="selectedKey"
  (outKeySelected)="handlerKeySelected($event)"
/>

example-other.component.ts

import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import {
  LibsUiComponentsButtonsTabComponent,
  IButtonTab,
  IOtherConfig,
} from '@libs-ui/components-buttons-tab';

@Component({
  selector: 'app-example-other',
  standalone: true,
  imports: [LibsUiComponentsButtonsTabComponent],
  templateUrl: './example-other.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleOtherComponent {
  protected selectedKey = model<string>('custom-1');

  protected readonly otherConfig: IOtherConfig = {
    color: '#0ea5e9',
    background: '#e0f2fe',
    background_badge: '#bae6fd',
  };

  protected readonly itemsOther: IButtonTab[] = [
    { key: 'custom-1', label: 'Custom 1', type: 'other' },
    { key: 'custom-2', label: 'Custom 2', type: 'other', count: 7,   modeCount: 'x+' },
    { key: 'custom-3', label: 'Custom 3', type: 'other', count: 120, modeCount: 'x+' },
  ];

  protected handlerKeySelected(event: Event): void {
    event.stopPropagation();
  }
}

@Input()

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | [items] | Array<IButtonTab> | required | Danh sách tab cần hiển thị. Label sẽ được tự động escape HTML. | [items]="tabList" | | [(keySelected)] | string | '' | Key của tab đang được chọn. Hỗ trợ two-way binding qua model(). | [(keySelected)]="activeKey" | | [disable] | boolean | false | Disable toàn bộ component, ngăn người dùng chọn bất kỳ tab nào. | [disable]="isLoading()" | | [otherConfig] | IOtherConfig \| undefined | undefined | Cấu hình màu tuỳ biến cho tab có type = 'other'. Chỉ áp dụng khi có ít nhất 1 tab dùng type = 'other'. | [otherConfig]="customColor" |

@Output()

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outKeySelected) | string | Emit key của tab vừa được chọn. Không emit khi tab bị disable. | handlerKeySelected(event: Event): void { event.stopPropagation(); } | (outKeySelected)="handlerKeySelected($event)" |

Lưu ý: outKeySelected emit giá trị string (key của tab), không phải Event. Tham số trong handler là key: string, không phải event: Event. Xem ví dụ thực tế trong mục Ví dụ sử dụng ở trên — handler nhận (event: Event) từ DOM click nhưng outKeySelected truyền key: string.

Ví dụ handler nhận đúng kiểu:

// HTML: (outKeySelected)="handlerTabChange($event)"
protected handlerTabChange(key: string): void {
  // key là string (key của tab vừa chọn)
  this.activeKey.set(key);
}

Types & Interfaces

import { IButtonTab, IOtherConfig, TYPE_BUTTON_TAB } from '@libs-ui/components-buttons-tab';

IButtonTab

Interface định nghĩa cấu hình cho từng tab item.

export interface IButtonTab {
  /** Key định danh duy nhất cho tab, dùng để two-way binding và emit */
  key: string;

  /** Nhãn hiển thị. Hỗ trợ i18n key. Sẽ được tự động escape HTML. */
  label: string;

  /** Màu/kiểu tab. Dùng một trong các giá trị có sẵn hoặc 'other' để tuỳ biến. */
  type: TYPE_BUTTON_TAB;

  /** Số hiển thị trên badge. Không truyền = không hiển thị badge. */
  count?: number;

  /**
   * Chế độ hiển thị badge:
   * - `'x'`: Số thường (1, 5, 15, 100)
   * - `'0x'`: Có số 0 đằng trước nếu < 10 (01, 05)
   * - `'x+'`: Hiển thị "maxCount+" khi vượt ngưỡng (99+)
   * @default 'x+'
   */
  modeCount?: TYPE_BADGE_MODE;

  /** Ngưỡng tối đa cho chế độ 'x+'. Khi count > maxCount sẽ hiển thị "maxCount+". @default 99 */
  maxCount?: number;

  /** CSS class tuỳ chỉnh cho wrapper tab item. Mặc định: `'px-[8px] mx-[8px] py-[4px]'` */
  class?: string;

  /** CSS class tuỳ chỉnh cho label. Mặc định: `'libs-ui-font-h6r'` */
  classLabel?: string;

  /** Disable tab item này. Người dùng không thể chọn tab khi disable = true. */
  disable?: boolean;

  /** Dữ liệu tuỳ ý kèm theo tab item, không ảnh hưởng đến hiển thị. */
  data?: any;
}

IOtherConfig

Cấu hình màu tuỳ biến cho tab có type = 'other'. Nếu không truyền backgroundbackground_badge, component tự tính màu nền từ color theo thang độ tương phản.

export interface IOtherConfig {
  /** Màu chữ và màu số badge khi tab đang active. Dạng hex: '#0ea5e9' */
  color: string;

  /** Màu nền tab khi active. Nếu không truyền, tự động tính từ color (95% contrast). */
  background?: string;

  /** Màu nền badge khi active. Nếu không truyền, tự động tính từ color (90% contrast). */
  background_badge?: string;
}

TYPE_BUTTON_TAB

export type TYPE_BUTTON_TAB =
  | 'blue'
  | 'green'
  | 'red'
  | 'orange'
  | 'yellow'
  | 'cyan'
  | 'purple'
  | 'brown'
  | 'other'
  | string;

Có 8 màu định sẵn. Dùng 'other' kết hợp với [otherConfig] để tuỳ biến màu hoàn toàn. Truyền string tuỳ ý được phép nhưng sẽ không có style mặc định nếu CSS tương ứng chưa tồn tại.

Lưu ý quan trọng

⚠️ otherConfig chỉ áp dụng cho tab có type = 'other': Nếu bạn dùng [otherConfig] nhưng không có tab nào có type = 'other', cấu hình này sẽ không có tác dụng. Các tab với type khác (blue, green...) không bị ảnh hưởng bởi otherConfig.

⚠️ Two-way binding với Signal: Khi dùng [(keySelected)] với Angular Signals, đảm bảo biến được khai báo bằng model<string>('') (không dùng signal()). model() mới hỗ trợ two-way binding đúng chuẩn Angular.

⚠️ outKeySelected emit string, không phải Event: Output này emit key: string của tab vừa chọn. Handler nhận string, không phải DOM Event. Xem ví dụ handler đúng trong mục Ví dụ sử dụng.

⚠️ Tab bị disable không emit event: Khi disable = true (toàn bộ) hoặc item.disable = true (từng tab), click sẽ không có tác dụng và outKeySelected sẽ không được emit.

⚠️ Label được escape HTML tự động: Giá trị label trong IButtonTab sẽ bị escape HTML trước khi hiển thị để tránh XSS. Không truyền HTML raw vào label.

Demo

npx nx serve core-ui

Truy cập: http://localhost:4500/buttons/tab