ngx-st-tri-state-checkbox
v19.0.0
Published
- [Overview](#overview) - [Installation](#installation) - [Basic Usage](#basic-usage) - [Inputs](#inputs) - [Integration with Forms](#integration-with-forms) - [Usage Examples](#usage-examples) - [Best Practices](#best-practices)
Downloads
268
Readme
Tri-State Checkbox Component - Complete Documentation
Table of Contents
Overview
The ngx-st-tri-state-checkbox component is a checkbox with three states (null/indeterminate, true, false) that cycles through values on click. Features include:
- Three-state checkbox (indeterminate, checked, unchecked)
- Customizable state sequence
- Full Angular Forms integration (ControlValueAccessor)
- Material Design styling
- Disabled state support
Installation
npm install ngx-st-tri-state-checkboxImport the module:
import { NgxStTriStateCheckboxModule } from 'ngx-st-tri-state-checkbox';
@NgModule({
imports: [NgxStTriStateCheckboxModule]
})
export class AppModule { }Basic Usage
With ngModel
<ngx-st-tri-state-checkbox
[(ngModel)]="value">
</ngx-st-tri-state-checkbox>
<p>Current value: {{ value }}</p>With Reactive Forms
// Component
form = this.fb.group({
status: [null]
});<form [formGroup]="form">
<ngx-st-tri-state-checkbox
formControlName="status">
</ngx-st-tri-state-checkbox>
</form>
<p>Current value: {{ form.get('status')?.value }}</p>Inputs
tape
- Type:
any[] - Default:
[null, true, false] - Description: Array of values that the checkbox cycles through on each click. The component will loop through these values in order.
- Example:
<!-- Default: null -> true -> false -> null --> [tape]="[null, true, false]" <!-- Custom: 0 -> 1 -> 2 -> 0 --> [tape]="[0, 1, 2]" <!-- String values: 'unknown' -> 'yes' -> 'no' --> [tape]="['unknown', 'yes', 'no']" <!-- Two states only: false -> true -> false --> [tape]="[false, true]"
Integration with Forms
The component implements ControlValueAccessor, making it compatible with Angular Forms (both template-driven and reactive).
Template-Driven Forms
// Component
export class MyComponent {
myValue: boolean | null = null;
}<ngx-st-tri-state-checkbox
[(ngModel)]="myValue"
name="tristate">
</ngx-st-tri-state-checkbox>Reactive Forms
// Component
export class MyComponent {
form = this.fb.group({
approved: [null],
enabled: [false],
status: ['pending']
});
}<form [formGroup]="form">
<ngx-st-tri-state-checkbox
formControlName="approved">
</ngx-st-tri-state-checkbox>
<ngx-st-tri-state-checkbox
formControlName="enabled"
[tape]="[false, true]">
</ngx-st-tri-state-checkbox>
<ngx-st-tri-state-checkbox
formControlName="status"
[tape]="['pending', 'approved', 'rejected']">
</ngx-st-tri-state-checkbox>
</form>Disabled State
// Component
form = this.fb.group({
status: [{ value: null, disabled: true }]
});
// Or programmatically
this.form.get('status')?.disable();<ngx-st-tri-state-checkbox
formControlName="status">
</ngx-st-tri-state-checkbox>Usage Examples
Example 1: Basic Tri-State Checkbox
// Component
@Component({
selector: 'app-basic-tristate',
template: `
<h3>Approval Status</h3>
<ngx-st-tri-state-checkbox
[(ngModel)]="approvalStatus">
</ngx-st-tri-state-checkbox>
<p>Status: {{ getStatusLabel() }}</p>
`
})
export class BasicTristateComponent {
approvalStatus: boolean | null = null;
getStatusLabel(): string {
if (this.approvalStatus === null) return 'Pending';
if (this.approvalStatus === true) return 'Approved';
return 'Rejected';
}
}Example 2: Custom State Sequence
// Component
@Component({
selector: 'app-custom-states',
template: `
<h3>Priority Level</h3>
<ngx-st-tri-state-checkbox
[(ngModel)]="priority"
[tape]="priorityLevels">
</ngx-st-tri-state-checkbox>
<p>Priority: {{ getPriorityLabel() }}</p>
`
})
export class CustomStatesComponent {
priority: string = 'low';
priorityLevels = ['low', 'medium', 'high'];
getPriorityLabel(): string {
return this.priority.toUpperCase();
}
}Example 3: Filter with Tri-State
// Component
@Component({
selector: 'app-filter',
template: `
<div class="filter-section">
<label>Show Active Users:</label>
<ngx-st-tri-state-checkbox
[(ngModel)]="activeFilter"
[tape]="[null, true, false]">
</ngx-st-tri-state-checkbox>
<span>{{ getFilterLabel() }}</span>
</div>
<div class="users-list">
<div *ngFor="let user of filteredUsers">
{{ user.name }} - {{ user.active ? 'Active' : 'Inactive' }}
</div>
</div>
`
})
export class FilterComponent {
activeFilter: boolean | null = null;
users = [
{ name: 'John', active: true },
{ name: 'Jane', active: false },
{ name: 'Bob', active: true }
];
get filteredUsers() {
if (this.activeFilter === null) {
return this.users; // Show all
}
return this.users.filter(u => u.active === this.activeFilter);
}
getFilterLabel(): string {
if (this.activeFilter === null) return 'All users';
if (this.activeFilter === true) return 'Active only';
return 'Inactive only';
}
}Example 4: Form with Multiple Tri-State Checkboxes
// Component
@Component({
selector: 'app-permission-form',
template: `
<form [formGroup]="permissionsForm">
<div class="permission-item">
<label>Read Access:</label>
<ngx-st-tri-state-checkbox
formControlName="read"
[tape]="accessLevels">
</ngx-st-tri-state-checkbox>
<span>{{ getAccessLabel(permissionsForm.get('read')?.value) }}</span>
</div>
<div class="permission-item">
<label>Write Access:</label>
<ngx-st-tri-state-checkbox
formControlName="write"
[tape]="accessLevels">
</ngx-st-tri-state-checkbox>
<span>{{ getAccessLabel(permissionsForm.get('write')?.value) }}</span>
</div>
<div class="permission-item">
<label>Delete Access:</label>
<ngx-st-tri-state-checkbox
formControlName="delete"
[tape]="accessLevels">
</ngx-st-tri-state-checkbox>
<span>{{ getAccessLabel(permissionsForm.get('delete')?.value) }}</span>
</div>
<button (click)="save()">Save Permissions</button>
</form>
`
})
export class PermissionFormComponent {
accessLevels = ['denied', 'inherited', 'allowed'];
permissionsForm = this.fb.group({
read: ['inherited'],
write: ['inherited'],
delete: ['denied']
});
constructor(private fb: FormBuilder) {}
getAccessLabel(value: string): string {
const labels = {
'denied': '❌ Denied',
'inherited': '↗️ Inherited',
'allowed': '✅ Allowed'
};
return labels[value] || value;
}
save(): void {
console.log('Permissions:', this.permissionsForm.value);
}
}Example 5: Boolean-Only Toggle (Two States)
// Component
@Component({
selector: 'app-toggle',
template: `
<div class="toggle-switch">
<label>Enable Feature:</label>
<ngx-st-tri-state-checkbox
[(ngModel)]="featureEnabled"
[tape]="[false, true]">
</ngx-st-tri-state-checkbox>
<span>{{ featureEnabled ? 'Enabled' : 'Disabled' }}</span>
</div>
`
})
export class ToggleComponent {
featureEnabled = false;
}Example 6: Table Column Filter
// Component
@Component({
selector: 'app-table-filter',
template: `
<table>
<thead>
<tr>
<th>
Name
<ngx-st-tri-state-checkbox
[(ngModel)]="sortName"
[tape]="[null, 'asc', 'desc']">
</ngx-st-tri-state-checkbox>
</th>
<th>
Active
<ngx-st-tri-state-checkbox
[(ngModel)]="filterActive">
</ngx-st-tri-state-checkbox>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of sortedAndFilteredData">
<td>{{ item.name }}</td>
<td>{{ item.active }}</td>
</tr>
</tbody>
</table>
`
})
export class TableFilterComponent {
sortName: 'asc' | 'desc' | null = null;
filterActive: boolean | null = null;
data = [
{ name: 'Alice', active: true },
{ name: 'Bob', active: false },
{ name: 'Charlie', active: true }
];
get sortedAndFilteredData() {
let result = [...this.data];
// Filter
if (this.filterActive !== null) {
result = result.filter(item => item.active === this.filterActive);
}
// Sort
if (this.sortName === 'asc') {
result.sort((a, b) => a.name.localeCompare(b.name));
} else if (this.sortName === 'desc') {
result.sort((a, b) => b.name.localeCompare(a.name));
}
return result;
}
}Example 7: Settings with Default/Enabled/Disabled
// Component
@Component({
selector: 'app-settings',
template: `
<h3>Notification Settings</h3>
<div class="setting-row" *ngFor="let setting of settings">
<label>{{ setting.label }}:</label>
<ngx-st-tri-state-checkbox
[(ngModel)]="setting.value"
[tape]="['default', 'enabled', 'disabled']">
</ngx-st-tri-state-checkbox>
<span class="setting-value">{{ getSettingDisplay(setting.value) }}</span>
</div>
<button (click)="saveSettings()">Save</button>
`
})
export class SettingsComponent {
settings = [
{ label: 'Email Notifications', value: 'default' },
{ label: 'Push Notifications', value: 'default' },
{ label: 'SMS Notifications', value: 'disabled' }
];
getSettingDisplay(value: string): string {
const display = {
'default': '⚙️ Use Default',
'enabled': '✅ Enabled',
'disabled': '❌ Disabled'
};
return display[value] || value;
}
saveSettings(): void {
console.log('Saving settings:', this.settings);
}
}Best Practices
Use meaningful state sequences that match your use case:
<!-- For filters: null (all), true (yes), false (no) --> [tape]="[null, true, false]" <!-- For sorting: null (none), 'asc', 'desc' --> [tape]="[null, 'asc', 'desc']" <!-- For permissions: 'denied', 'inherited', 'allowed' --> [tape]="['denied', 'inherited', 'allowed']"Provide visual feedback showing the current state:
<ngx-st-tri-state-checkbox [(ngModel)]="value"></ngx-st-tri-state-checkbox> <span>{{ getStateLabel(value) }}</span>Use with reactive forms for better control and validation:
form = this.fb.group({ status: [null, Validators.required] });Initialize with appropriate default values:
// For filters, often start with null (show all) filterValue: boolean | null = null; // For toggles, often start with false enabled = false; // For status, start with pending/default status = 'pending';Document the state sequence for other developers:
// States: null (pending) -> true (approved) -> false (rejected) [tape]="[null, true, false]"
State Cycling Behavior
The checkbox cycles through states in the order defined by the tape input:
// Default: [null, true, false]
Click 1: null -> true
Click 2: true -> false
Click 3: false -> null (loops back)
Click 4: null -> true (continues...)
// Custom: ['off', 'on', 'auto']
Click 1: 'off' -> 'on'
Click 2: 'on' -> 'auto'
Click 3: 'auto' -> 'off' (loops back)Visual States
The component uses Material Design checkbox which shows:
- Indeterminate (dash/minus): Usually for
nullor first state - Checked: Usually for
trueor second state - Unchecked: Usually for
falseor third state
For custom tape values, the visual representation follows the same pattern based on position in the array.
Common Use Cases
- Filters: null (all), true (include), false (exclude)
- Sorting: null (none), 'asc', 'desc'
- Permissions: 'denied', 'inherited', 'allowed'
- Status: 'pending', 'approved', 'rejected'
- Toggle: false, true (two-state)
- Priority: 'low', 'medium', 'high'
This documentation covers all inputs, behavior, and usage patterns for the Tri-State Checkbox component.
