@libs-ui/components-buttons-group
v0.2.355-15
Published
> Component Button Group cho phép nhóm nhiều button thành một nhóm liền kề với trạng thái active.
Readme
@libs-ui/components-buttons-group
Component Button Group cho phép nhóm nhiều button thành một nhóm liền kề với trạng thái active.
Giới thiệu
LibsUiComponentsButtonsGroupComponent là một standalone Angular component được thiết kế để hiển thị một nhóm các button liền kề nhau. Component hỗ trợ quản lý trạng thái active và cho phép chuyển đổi giữa các button trong nhóm.
Tính năng
- ✅ Nhóm nhiều button thành một group liền kề
- ✅ Quản lý trạng thái active với visual feedback rõ ràng
- ✅ Two-way binding cho index button đang active
- ✅ Hỗ trợ disable toàn bộ group hoặc từng button
- ✅ Tích hợp popover cho từng button
- ✅ Hỗ trợ icon cho button
- ✅ Tự động xử lý border radius cho button đầu/cuối/giữa
- ✅ Angular Signals cho tính phản hồi cao
- ✅ OnPush Change Detection tối ưu hiệu năng
Khi nào sử dụng
- Khi cần nhóm các button có liên quan với nhau
- Khi cần toggle giữa các options (như tab buttons)
- Khi cần hiển thị một nhóm actions liền kề
- Phù hợp cho filter groups, view switchers, segmented controls
Cài đặt
# npm
npm install @libs-ui/components-buttons-group
# yarn
yarn add @libs-ui/components-buttons-groupImport
import { LibsUiComponentsButtonsGroupComponent } from '@libs-ui/components-buttons-group';
import { IButton } from '@libs-ui/components-buttons-button';
@Component({
standalone: true,
imports: [LibsUiComponentsButtonsGroupComponent],
// ...
})
export class YourComponent {}Ví dụ
Basic Usage
<libs_ui-components-buttons-group
[buttons]="viewButtons"
[(indexActive)]="activeIndex"
(outChange)="handleChange($event)" />viewButtons: IButton[] = [
{ label: 'List View', key: 'list' },
{ label: 'Grid View', key: 'grid' },
{ label: 'Card View', key: 'card' }
];
activeIndex = 0;
handleChange(button: IButton) {
console.log('Selected:', button);
}With Icons
<libs_ui-components-buttons-group
[buttons]="viewButtonsWithIcons"
[(indexActive)]="activeView" />viewButtonsWithIcons: IButton[] = [
{
label: 'List',
key: 'list',
classIconLeft: 'libs-ui-icon-list'
},
{
label: 'Grid',
key: 'grid',
classIconLeft: 'libs-ui-icon-grid'
},
{
label: 'Card',
key: 'card',
classIconLeft: 'libs-ui-icon-card'
}
];
activeView = 0;Icon Only Buttons
<libs_ui-components-buttons-group
[buttons]="iconOnlyButtons"
[(indexActive)]="selectedIndex" />iconOnlyButtons: IButton[] = [
{
key: 'bold',
classIconLeft: 'libs-ui-icon-bold',
iconOnlyType: true
},
{
key: 'italic',
classIconLeft: 'libs-ui-icon-italic',
iconOnlyType: true
},
{
key: 'underline',
classIconLeft: 'libs-ui-icon-underline',
iconOnlyType: true
}
];With Disabled State
<!-- Disable entire group -->
<libs_ui-components-buttons-group
[buttons]="buttons"
[disable]="true"
[(indexActive)]="activeIndex" />
<!-- Disable specific buttons -->
<libs_ui-components-buttons-group
[buttons]="buttonsWithDisabled"
[(indexActive)]="activeIndex" />buttonsWithDisabled: IButton[] = [
{ label: 'Option 1', key: '1' },
{ label: 'Option 2', key: '2', disable: true },
{ label: 'Option 3', key: '3' }
];With Popover
<libs_ui-components-buttons-group
[buttons]="buttonsWithPopover"
[(indexActive)]="activeIndex"
(outFunctionsControl)="handlePopoverControl($event)" />buttonsWithPopover: IButton[] = [
{
label: 'Info',
key: 'info',
popover: {
content: 'This is information button',
mode: 'hover'
}
},
{
label: 'Warning',
key: 'warning',
popover: {
content: 'This is warning button',
mode: 'hover'
}
}
];
handlePopoverControl(control: IPopoverFunctionControlEvent) {
console.log('Popover control:', control);
}Filter Group Example
<libs_ui-components-buttons-group
[buttons]="filterButtons"
[(indexActive)]="activeFilter"
(outChange)="applyFilter($event)" />filterButtons: IButton[] = [
{ label: 'All', key: 'all' },
{ label: 'Active', key: 'active' },
{ label: 'Completed', key: 'completed' },
{ label: 'Archived', key: 'archived' }
];
activeFilter = 0;
applyFilter(button: IButton) {
// Apply filter based on button.key
console.log('Filtering by:', button.key);
}Custom Styling
<libs_ui-components-buttons-group
[buttons]="styledButtons"
[(indexActive)]="activeIndex" />styledButtons: IButton[] = [
{
label: 'Primary',
key: '1',
classInclude: 'custom-button-class'
},
{
label: 'Secondary',
key: '2',
classInclude: 'custom-button-class'
}
];API
libs_ui-components-buttons-group
Inputs
| Property | Type | Default | Description |
| ----------------- | ---------------- | -------- | ---------------------------------------------- |
| [buttons] | Array<IButton> | required | Danh sách các button trong group |
| [(indexActive)] | number | 0 | Index của button đang active (two-way binding) |
| [disable] | boolean | false | Disable toàn bộ button group |
Outputs
| Property | Type | Description |
| ----------------------- | ------------------------------ | --------------------------------- |
| (outChange) | IButton | Emit khi chuyển đổi button active |
| (outFunctionsControl) | IPopoverFunctionControlEvent | Emit functions điều khiển popover |
Public Methods
| Method | Description |
| ------------------ | --------------------------------------- |
| FunctionsControl | Getter để lấy popover control functions |
Types & Interfaces
IButton Interface
Button group sử dụng interface IButton từ @libs-ui/components-buttons-button:
export interface IButton {
/** Unique key cho button */
key?: string;
/** Kiểu button (sẽ được override bởi component) */
type?: TYPE_BUTTON;
/** Kích thước button */
sizeButton?: TYPE_SIZE_BUTTON;
/** Chỉ hiển thị icon, ẩn label */
iconOnlyType?: boolean;
/** Label hiển thị trên button */
label?: string;
/** Disable button này */
disable?: boolean;
/** Class CSS bổ sung */
classInclude?: string;
/** Class icon bên trái */
classIconLeft?: string;
/** Class icon bên phải */
classIconRight?: string;
/** Class cho label */
classLabel?: string;
/** Cấu hình popover */
popover?: IPopover;
/** Không stop propagation event */
ignoreStopPropagationEvent?: boolean;
/** Z-index cho button */
zIndex?: number;
/** Trạng thái pending */
isPending?: boolean;
/** Action callback */
action?: (data?: any) => Promise<void>;
/** Style cho icon trái */
styleIconLeft?: Record<string, any>;
/** Style cho button */
styleButton?: Record<string, any>;
/** Custom color (khi type là button-custom) */
buttonCustom?: IColorButton;
}TYPE_BUTTON
export type TYPE_BUTTON =
| 'button-primary'
| 'button-primary-revert'
| 'button-secondary'
| 'button-secondary-red'
| 'button-outline-secondary'
| 'button-third'
| 'button-outline'
| 'button-danger-high'
| 'button-outline-hover-danger'
| 'button-third-hover-danger'
| 'button-danger-low'
| 'button-green'
| 'button-violet'
| 'button-secondary-green'
| 'button-outline-green'
| 'button-custom'
| 'button-link-primary'
| 'button-link-third'
| 'button-link-danger-high'
| 'button-link-danger-low'
| 'button-link-green'
| 'button-link-violet'
| 'button-link-custom'
| string;TYPE_SIZE_BUTTON
export type TYPE_SIZE_BUTTON = 'large' | 'medium' | 'small' | 'smaller';Styling
Component tự động xử lý styling cho button group:
- First button: Border radius trái (top-left, bottom-left)
- Middle buttons: Không có border radius, border-left bị loại bỏ
- Last button: Border radius phải (top-right, bottom-right), border-left bị loại bỏ
- Active button: Sử dụng
button-primarytype - Inactive buttons: Sử dụng
button-primary-reverttype
CSS Variables
Component sử dụng CSS variable:
--libs-ui-button-other-color-border: #226ff5; // Border color cho disabled stateBehavior
Active State Management
- Khi click vào một button, nó sẽ trở thành active
- Click vào button đang active sẽ không có effect (không emit event)
- Index active được quản lý qua two-way binding
[(indexActive)] - Active button hiển thị với style
button-primary - Inactive buttons hiển thị với style
button-primary-revert
Disable Behavior
- Khi
[disable]="true": Toàn bộ group bị disable - Khi button cụ thể có
disable: true: Chỉ button đó bị disable - Disabled buttons vẫn giữ border styling phù hợp với vị trí trong group
Công nghệ
| Technology | Version | Purpose | | --------------- | ------- | ---------------- | | Angular | 18+ | Framework | | Angular Signals | - | State management | | SCSS | - | Styling | | OnPush | - | Change Detection |
Demo
npx nx serve core-uiTruy cập: http://localhost:4500/buttons/group
Unit Tests
# Chạy tests
npx nx test components-buttons-group
# Coverage
npx nx test components-buttons-group --coverage
# Watch mode
npx nx test components-buttons-group --watchDependencies
@angular/core: >=18.0.0@libs-ui/components-buttons-button: 0.2.355-14@libs-ui/components-popover: 0.2.355-14@ngx-translate/core: ^15.0.0
Important Notes
⚠️ Type Override
Component tự động override type property của buttons:
- Active button →
button-primary - Inactive button →
button-primary-revert
Nếu bạn muốn custom type, cần modify component source code.
⚠️ Border Styling
Component sử dụng ::ng-deep để style nested components. Điều này cần thiết để style các button components bên trong nhưng có thể ảnh hưởng đến global styles nếu không cẩn thận.
⚠️ Index-based Active State
Component sử dụng index thay vì key để quản lý active state. Đảm bảo array buttons không thay đổi thứ tự nếu bạn muốn maintain active state.
Best Practices
- Sử dụng key duy nhất: Luôn cung cấp
keyunique cho mỗi button để dễ identify - Limit số lượng buttons: Nên giới hạn 3-5 buttons trong một group để UX tốt
- Consistent labels: Sử dụng label ngắn gọn, rõ ràng và có độ dài tương đương
- Icon consistency: Nếu dùng icon, nên dùng cho tất cả buttons hoặc không dùng
- Responsive design: Cân nhắc sử dụng icon-only mode trên mobile
Troubleshooting
Button không chuyển active state
- Kiểm tra
[(indexActive)]binding - Đảm bảo không có logic nào block event handler
- Verify button không bị disable
Border styling không đúng
- Kiểm tra ViewEncapsulation của parent component
- Verify CSS variables được define
- Check xem có CSS conflicts không
Popover không hoạt động
- Đảm bảo đã import
@libs-ui/components-popover - Verify popover config đúng format
- Check z-index conflicts
License
MIT
