npm package: @ng-shangjc/checkbox
Description: Checkbox component source package for ng-shangjc angular components
Author: jc-develop
Latest version: 1.0.3-beta

<p align="center">
<a href="https://juliancallejas.github.io/ng-shangjc-docs">
  <img src="https://res.cloudinary.com/dphleqb5t/image/upload/v1772819746/shangjc/shangjc-64-bg-dark_kwzs81.svg" width="307" alt="Shangjc"  /> 
</a>
</p>

# Checkbox Component

A flexible and accessible checkbox component with support for indeterminate state, form integration, and multiple sizes. Built with Angular's standalone components and signals for optimal performance.

## Official Documentation

<a href="https://juliancallejas.github.io/ng-shangjc-docs/?path=/docs/components-checkbox">
    ng-Shangjc docs
</a>

## Features

- 🚀 **Signal-based State Management**: Uses Angular's signals for efficient change detection and reactive state management
- 🎨 **Multiple Size Variants**: Small (`sm`), default, and large (`lg`) sizes for different UI contexts
- ⚡ **Performance Optimized**: OnPush change detection strategy for optimal rendering performance
- 🎯 **Indeterminate State**: Support for mixed/indeterminate checkbox state, perfect for parent-child checkbox relationships
- ⌨️ **Keyboard Navigation**: Full keyboard support with Space and Enter keys for accessibility
- ♿ **Accessibility First**: Complete ARIA compliance with proper roles, states, and screen reader support
- 📝 **Form Integration**: Seamless integration with both template-driven and reactive forms via ControlValueAccessor
- 🏷️ **Content Projection**: Flexible content projection with dedicated label, description, and custom icon components
- 🎨 **Customizable Styling**: Built with class-variance-authority for consistent styling with Tailwind CSS
- 🔧 **Controlled & Uncontrolled**: Supports both controlled (parent-managed) and uncontrolled (internal) state patterns
- 🎯 **Type-Safe**: Full TypeScript support with strict type checking and comprehensive API
- 🌐 **RTL Support**: Right-to-left layout support for international applications
- 📱 **Responsive Design**: Works seamlessly across all device sizes and screen resolutions

## Installation

### Step 1: Install the CLI

First, install the ng-shangjc CLI globally or use npx:

```bash
# Install globally
npm install -g @ng-shangjc/cli

# or with yarn
yarn global add @ng-shangjc/cli

# or with pnpm
pnpm install -g @ng-shangjc/cli

# Or use npx without installation
npx @ng-shangjc/cli <command>
```

### Step 2: Initialize your project

If you haven't already, initialize your Angular project for ng-shangjc components:

```bash
ng-shangjc init
```

This will create a `shangjc.config.json` file and set up your project for component installations.

### Step 3: Install the component

Install the checkbox component into your project:

```bash
ng-shangjc install checkbox
```

The component will be installed in the configured path (default: `src/ui/shangjc`). Adjust the import path in your components based on your project structure and the configured installation path.

## Import

After installation, import the components from your configured installation path. The examples below use the default path `src/ui/shangjc` - adjust the path according to your project structure and configuration.

### Standalone Components (Recommended)

Import and use the individual components directly in your standalone components:

```typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { 
  CheckboxComponent,
  CheckboxLabelComponent,
  CheckboxDescriptionComponent,
  CheckboxIconComponent
} from './ui/shangjc/checkbox';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [
    CommonModule,
    CheckboxComponent,
    CheckboxLabelComponent,
    CheckboxDescriptionComponent,
    CheckboxIconComponent
  ],
  template: `
    <ng-shangjc-checkbox [(checked)]="acceptTerms">
      <ng-shangjc-checkbox-label>Accept terms and conditions</ng-shangjc-checkbox-label>
    </ng-shangjc-checkbox>
  `
})
export class ExampleComponent {
  acceptTerms = false;
}
```

### Using NgModule (Legacy)

If you're using NgModules, import the `CheckboxModule`:

```typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CheckboxModule } from './ui/shangjc/checkbox';

@NgModule({
  declarations: [YourComponent],
  imports: [
    CommonModule,
    CheckboxModule
  ]
})
export class YourModule { }
```

Then use the components in your templates:

```html
<ng-shangjc-checkbox [(checked)]="acceptTerms">
  <ng-shangjc-checkbox-label>Accept terms and conditions</ng-shangjc-checkbox-label>
</ng-shangjc-checkbox>
```

## Basic Usage

### Default Example

```typescript
import { Component } from '@angular/core';
import { 
  CheckboxComponent,
  CheckboxLabelComponent,
  CheckboxDescriptionComponent
} from './ui/shangjc/checkbox';

@Component({
  selector: 'app-basic-checkbox',
  standalone: true,
  imports: [
    CheckboxComponent,
    CheckboxLabelComponent,
    CheckboxDescriptionComponent
  ],
  template: `
    <div class="space-y-4">
      <!-- Basic checkbox -->
      <ng-shangjc-checkbox [(checked)]="basicChecked">
        <ng-shangjc-checkbox-label>Enable notifications</ng-shangjc-checkbox-label>
      </ng-shangjc-checkbox>

      <!-- Checkbox with description -->
      <ng-shangjc-checkbox [(checked)]="newsletterChecked">
        <ng-shangjc-checkbox-label>Subscribe to newsletter</ng-shangjc-checkbox-label>
        <ng-shangjc-checkbox-description>
          Get the latest updates and news delivered to your inbox weekly.
        </ng-shangjc-checkbox-description>
      </ng-shangjc-checkbox>
    </div>
  `
})
export class BasicCheckboxComponent {
  basicChecked = false;
  newsletterChecked = true;
}
```

### Alternative Usage Patterns

#### Indeterminate State

```typescript
@Component({
  selector: 'app-indeterminate-example',
  standalone: true,
  imports: [CheckboxComponent, CheckboxLabelComponent],
  template: `
    <ng-shangjc-checkbox 
      [indeterminate]="isIndeterminate" 
      [checked]="allSelected"
      (checkedChange)="onSelectAllChange($event)">
      <ng-shangjc-checkbox-label>Select all items</ng-shangjc-checkbox-label>
    </ng-shangjc-checkbox>
  `
})
export class IndeterminateExampleComponent {
  allSelected = false;
  isIndeterminate = false;
  
  onSelectAllChange(checked: boolean) {
    this.allSelected = checked;
    this.isIndeterminate = false;
  }
}
```

#### Size Variants

```typescript
@Component({
  selector: 'app-sizes-example',
  standalone: true,
  imports: [CheckboxComponent, CheckboxLabelComponent],
  template: `
    <div class="space-y-3">
      <ng-shangjc-checkbox size="sm" [(checked)]="smallChecked">
        <ng-shangjc-checkbox-label>Small checkbox</ng-shangjc-checkbox-label>
      </ng-shangjc-checkbox>
      
      <ng-shangjc-checkbox size="default" [(checked)]="defaultChecked">
        <ng-shangjc-checkbox-label>Default checkbox</ng-shangjc-checkbox-label>
      </ng-shangjc-checkbox>
      
      <ng-shangjc-checkbox size="lg" [(checked)]="largeChecked">
        <ng-shangjc-checkbox-label>Large checkbox</ng-shangjc-checkbox-label>
      </ng-shangjc-checkbox>
    </div>
  `
})
export class SizesExampleComponent {
  smallChecked = false;
  defaultChecked = false;
  largeChecked = false;
}
```

## Advanced Usage

### Controlled Component

```typescript
import { Component, signal } from '@angular/core';
import { CheckboxComponent, CheckboxLabelComponent, CheckboxDescriptionComponent } from './ui/shangjc/checkbox';

@Component({
  selector: 'app-controlled-example',
  standalone: true,
  imports: [CheckboxComponent, CheckboxLabelComponent, CheckboxDescriptionComponent],
  template: `
    <div class="space-y-4">
      <ng-shangjc-checkbox
        [checked]="controlledState()"
        [indeterminate]="isIndeterminate()"
        (checkedChange)="toggleState()"
        [disabled]="isDisabled()"
      >
        <ng-shangjc-checkbox-label>Controlled checkbox</ng-shangjc-checkbox-label>
        <ng-shangjc-checkbox-description>
          State is managed by the parent component using signals
        </ng-shangjc-checkbox-description>
      </ng-shangjc-checkbox>
      
      <div class="flex gap-2">
        <button (click)="toggleState()">Toggle</button>
        <button (click)="setIndeterminate()">Set Indeterminate</button>
        <button (click)="toggleDisabled()">Toggle Disabled</button>
      </div>
      
      <p>State: {{ controlledState() ? 'Checked' : 'Unchecked' }}</p>
      <p>Indeterminate: {{ isIndeterminate() ? 'Yes' : 'No' }}</p>
      <p>Disabled: {{ isDisabled() ? 'Yes' : 'No' }}</p>
    </div>
  `
})
export class ControlledExampleComponent {
  controlledState = signal(false);
  isIndeterminate = signal(false);
  isDisabled = signal(false);
  
  toggleState() {
    this.controlledState.set(!this.controlledState());
    this.isIndeterminate.set(false);
  }
  
  setIndeterminate() {
    this.isIndeterminate.set(!this.isIndeterminate());
  }
  
  toggleDisabled() {
    this.isDisabled.set(!this.isDisabled());
  }
}
```

### Reactive Forms Integration

```typescript
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { CheckboxComponent, CheckboxLabelComponent, CheckboxDescriptionComponent } from './ui/shangjc/checkbox';

@Component({
  selector: 'app-form-example',
  standalone: true,
  imports: [
    ReactiveFormsModule,
    CheckboxComponent,
    CheckboxLabelComponent,
    CheckboxDescriptionComponent
  ],
  template: `
    <form [formGroup]="settingsForm" (ngSubmit)="onSubmit()" class="space-y-4">
      <ng-shangjc-checkbox formControlName="terms" id="terms">
        <ng-shangjc-checkbox-label>I accept the terms and conditions</ng-shangjc-checkbox-label>
        <ng-shangjc-checkbox-description>Required to continue using our service</ng-shangjc-checkbox-description>
      </ng-shangjc-checkbox>
      
      @if (settingsForm.get('terms')?.touched && settingsForm.get('terms')?.errors?.['required']) {
        <div class="text-sm text-red-600">
          You must accept the terms and conditions to continue
        </div>
      }
      
      <ng-shangjc-checkbox formControlName="newsletter" id="newsletter">
        <ng-shangjc-checkbox-label>Subscribe to newsletter</ng-shangjc-checkbox-label>
        <ng-shangjc-checkbox-description>Get updates about new features</ng-shangjc-checkbox-description>
      </ng-shangjc-checkbox>
      
      <button type="submit" [disabled]="settingsForm.invalid">Submit</button>
    </form>
  `
})
export class FormExampleComponent implements OnInit {
  settingsForm: FormGroup;
  
  constructor(private fb: FormBuilder) {}
  
  ngOnInit() {
    this.settingsForm = this.fb.group({
      terms: [false, Validators.requiredTrue],
      newsletter: [true]
    });
  }
  
  onSubmit() {
    if (this.settingsForm.valid) {
      console.log('Form submitted:', this.settingsForm.value);
    }
  }
}
```

## API Reference

### CheckboxComponent

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `id` | `string` | `cbx-<random>` | Unique identifier for the checkbox |
| `checked` | `boolean` | `false` | Whether the checkbox is checked |
| `indeterminate` | `boolean` | `false` | Whether the checkbox is in indeterminate state |
| `disabled` | `boolean` | `false` | Whether the checkbox is disabled |
| `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Size variant of the checkbox |
| `class` | `string` | `''` | Additional CSS classes to apply |
| `checkedClass` | `string` | `''` | Additional CSS classes for checked state |
| `ariaLabel` | `string` | `undefined` | ARIA label for accessibility |
| `ariaDescribedby` | `string` | `undefined` | ARIA describedby for additional context |

#### Events

| Event | Type | Description |
|-------|------|-------------|
| `checkedChange` | `EventEmitter<boolean>` | Emitted when the checkbox state changes |

### Subcomponents

#### CheckboxLabelComponent

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `class` | `string` | `''` | Additional CSS classes to apply |

#### CheckboxDescriptionComponent

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `class` | `string` | `''` | Additional CSS classes to apply |

#### CheckboxIconComponent

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `class` | `string` | `''` | Additional CSS classes to apply |
| `ariaLabel` | `string` | `undefined` | ARIA label for the icon |
| `ariaDescribedby` | `string` | `undefined` | ARIA describedby for the icon |

## Accessibility

- **Keyboard Navigation**: Full support for Space and Enter keys to toggle checkbox state
- **ARIA Attributes**: Proper `aria-checked`, `aria-disabled`, `aria-label`, and `aria-describedby` attributes
- **Focus Management**: Visible focus indicators and proper focus handling
- **Screen Reader**: Compatible with screen readers and assistive technologies
- **Semantic Structure**: Uses proper HTML semantic elements and roles
- **Indeterminate State**: Properly communicates indeterminate state to assistive technologies

### ARIA Features

- `role="checkbox"` on the checkbox button element
- `aria-checked` with values `true`, `false`, or `mixed` for indeterminate state
- `aria-disabled` indicates when the checkbox is disabled
- `aria-label` provides accessible labeling when text labels are not available
- `aria-describedby` references additional descriptive content

## Browser Support

- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+

## Contributing

See the main project [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.

---

**Part of ng-shangjc component library** • [Documentation](https://juliancallejas.github.io/ng-shangjc-docs/)

<p align="center">
<a href="https://github.com/JulianCallejas">
  <img src="https://res.cloudinary.com/dphleqb5t/image/upload/v1740784502/github-jc-develop/JC-LOGO-Horizontal-170-50-thin-github_uu3b5n.svg" width="170" alt="{ jc - develop }"  /> 
</a>
</p>