If this plugin is useful to you, consider giving it a ⭐ on GitHub.
This plugin provides a hierarchical checkbox tree component for Filament forms. Display checkboxes in a parent-child tree structure with automatic state management.
This component extends Filament's native CheckboxList component, ensuring seamless integration with the Filament ecosystem while adding powerful hierarchical capabilities:
Preserved CheckboxList Features:
- All validation methods (
required(),rules(), etc.) - Bulk actions (
bulkToggleable(),selectAllAction(),deselectAllAction()) - Search functionality (
searchable(),searchPrompt()) - Disabled state (
disabled()) - Relationship handling (
relationship()) - State management methods (
default(),dehydrateStateUsing()) - HTML support (
allowHtml()) - Splitting options into columns (
columns(),gridDirection()) - Full compatibility with Filament's styling system and dark mode
Enhanced for Hierarchical Use:
- Descriptions: Integrated directly into the options array structure for better organization
- State Management: Intelligent parent-child state synchronization with indeterminate states
- Data Storage: Configurable leaf-only or full hierarchy storage
- Tree Operations: Collapsible sections and parent-child selection logic
This architecture ensures you get all the familiar CheckboxList functionality plus powerful new features specifically designed for hierarchical data structures.
- Hierarchical Structure - Display checkboxes in unlimited nested levels
- Parent-Child Control - Checking a parent automatically selects all children
- Indeterminate States - Visual indication when only some children are selected
- Collapsible Sections - Expand/collapse parent nodes with smooth animations
- Search - Filter tree items by keyword, shows parents when children match
- Bulk Actions - Select all / Deselect all buttons with customizable labels
- Native Filament Styling - Uses Filament's checkbox component, works with custom themes
- Dark Mode Support - Fully compatible with Filament's dark mode
- Flat Array Storage - Stores selections as a simple array, compatible with JSON columns and relationships
- Check a parent - All children become checked, parent shows as checked
- Uncheck a parent - All children become unchecked
- Check some children - Parent shows indeterminate state (dash)
- Check all children - Parent automatically becomes checked
- Uncheck all children - Parent automatically becomes unchecked
- Permission management with grouped permissions
- Category/subcategory selection
- Feature flags with hierarchical options
- Department/team hierarchies
- Any multi-level checkbox selection
- PHP 8.1+
- Laravel 10.x+
- Filament 3.x
Install via Composer:
composer require promethys/checkbox-treePublish Filament assets (required):
php artisan filament:assetsClear caches:
php artisan optimize:clearuse Promethys\CheckboxTree\CheckboxTree;
CheckboxTree::make('permissions')
->label('Permissions')
->options([
'user_management' => [
'label' => 'User Management',
'children' => [
'create_users' => 'Create Users',
'edit_users' => 'Edit Users',
'delete_users' => 'Delete Users',
],
],
'content_management' => [
'label' => 'Content Management',
'children' => [
'create_posts' => 'Create Posts',
'edit_posts' => 'Edit Posts',
'publish_posts' => 'Publish Posts',
],
],
])By default, only leaf nodes (items without children) are stored:
['create_users', 'edit_users', 'delete_users']This works seamlessly with:
- JSON database columns
- Pivot tables via Filament relationships
- Simple array storage
To include parent keys in the stored value, use storeParentKeys():
CheckboxTree::make('permissions')
->storeParentKeys()
->options([...])
// Stored value: ['user_management', 'create_users', 'edit_users', 'delete_users']You can provide flat options with parent_id references instead of manually nesting:
CheckboxTree::make('permissions')
->hierarchical('parent_id')
->options([
'user_management' => ['label' => 'User Management', 'parent_id' => null],
'create_users' => ['label' => 'Create Users', 'parent_id' => 'user_management'],
'edit_users' => ['label' => 'Edit Users', 'parent_id' => 'user_management'],
'delete_users' => ['label' => 'Delete Users', 'parent_id' => 'user_management'],
'post_management' => ['label' => 'Post Management', 'parent_id' => null],
'create_posts' => ['label' => 'Create Posts', 'parent_id' => 'post_management'],
])The component automatically builds the tree structure. Items with parent_id => null become root items.
The label field must be label. Falls back to the array key if label is not provided.
Add description text below checkbox labels:
CheckboxTree::make('permissions')
->options([
'admin' => [
'label' => 'Administrator',
'description' => 'Full system access',
'children' => [
'manage_users' => [
'label' => 'Manage Users',
'description' => 'Create, edit, and delete users',
],
'manage_settings' => 'Manage Settings',
],
],
])Descriptions are optional and displayed in smaller, muted text below the label.
By default, Filament escapes any HTML in option labels (native behavior inherited from CheckboxList). If you'd like to allow HTML, you can use the allowHtml() method. The plugin supports HTML formatting for both labels and descriptions:
CheckboxTree::make('permissions')
->options([
'admin' => [
'label' => '<span class="text-blue-500">Administrator</span>',
'description' => '<span class="text-xs">Full system access</span>',
'children' => [
'manage_users' => [
'label' => '<span class="text-blue-500">Manage Users</span>',
'description' => '<span class="text-xs">Create, edit, and delete users</span>',
],
'manage_settings' => 'Manage Settings',
],
],
])
->allowHtml()You can also use instances of Illuminate\Support\HtmlString or Illuminate\Contracts\Support\Htmlable. This approach provides better security and allows you to render HTML or even markdown:
CheckboxTree::make('permissions')
->options([
'admin' => [
'label' => new HtmlString('<strong>Administrator</strong>'),
'description' => str('**Full system** access')->inlineMarkdown()->toHtmlString(),
'children' => [
'manage_users' => [
'label' => new HtmlString('<strong>Manage Users</strong>'),
'description' => str('**Create**, **edit**, and **delete** users')->inlineMarkdown()->toHtmlString(),
],
'manage_settings' => new HtmlString('<strong>Manage Settings</strong>'),
],
],
])Security Warning: Always ensure that HTML content is safe to render. User-generated content should be properly sanitized to prevent XSS attacks.
The component supports unlimited nesting depth:
CheckboxTree::make('categories')
->options([
'electronics' => [
'label' => 'Electronics',
'children' => [
'computers' => [
'label' => 'Computers',
'children' => [
'laptops' => 'Laptops',
'desktops' => 'Desktops',
],
],
'phones' => 'Mobile Phones',
],
],
])Standard Filament validation works:
CheckboxTree::make('permissions')
->required()
->options([...])CheckboxTree::make('permissions')
->disabled()
->options([...])Disable individual options using a closure:
CheckboxTree::make('permissions')
->disableOptionWhen(fn (string $value): bool => $value === 'delete_users')
->options([...])When a parent is disabled, all its children are automatically disabled too:
// Disables "User Management" and all its children
CheckboxTree::make('permissions')
->disableOptionWhen(fn (string $value): bool => $value === 'user_management')
->options([...])When all children of a parent are disabled, the parent is automatically disabled as well:
// Disables all children of "User Management", so the parent becomes disabled too
CheckboxTree::make('permissions')
->disableOptionWhen(fn (string $value): bool => in_array($value, [
'create_users', 'edit_users', 'delete_users',
]))
->options([...])Enable collapsible parent nodes:
CheckboxTree::make('permissions')
->collapsible()
->options([...])Start with all sections collapsed:
CheckboxTree::make('permissions')
->collapsible(defaultCollapsed: true)
->options([...])Enable search to filter tree items:
CheckboxTree::make('permissions')
->searchable()
->options([...])Customize the search placeholder:
CheckboxTree::make('permissions')
->searchable()
->searchPrompt('Search permissions...')
->options([...])When searching, parent nodes are shown if any of their children match the search term.
Enable "Select all / Deselect all" buttons:
CheckboxTree::make('permissions')
->bulkToggleable()
->options([...])Customize the action labels:
CheckboxTree::make('technologies')
->bulkToggleable()
->selectAllAction(
fn ($action) => $action->label('Select all technologies')
)
->deselectAllAction(
fn ($action) => $action->label('Clear selection')
)
->options([...])Build a tree directly from a BelongsToMany relationship with hierarchical records:
// Model: Permission has parent_id column
CheckboxTree::make('permissions')
->relationship('permissions', 'name')
->hierarchical('parent_id')The component will:
- Fetch all related records from the pivot table
- Build a tree structure based on
parent_id - Save selected values back to the pivot table
With query modification:
CheckboxTree::make('permissions')
->relationship(
'permissions',
'name',
fn ($query) => $query->where('active', true)
)
->hierarchical('parent_id')Checkbox flickering in multi-column layouts — When using columns() with collapsible or searchable trees, checkboxes may occasionally flicker or briefly disappear during column reflow (collapse/expand, search filtering). This is a browser rendering bug with CSS multi-column layouts and dynamic content. The checkboxes remain functional — only the visual rendering is affected. Reloading the page or triggering a repaint (e.g. resizing the window) resolves it.
# Clone the repository
git clone https://github.com/promethys/checkbox-tree.git
# Install dependencies
composer install
npm install
# Build assets
npm run build
# Run tests
composer testSee CHANGELOG for recent changes.
If you encounter a bug or unexpected behavior, please help us help you by following these guidelines:
- Create an issue on GitHub: Create an issue on GitHub
- Describe the issue clearly: What did you try to do? What did you expect to happen? What actually happened?
- Include relevant code snippets: Show any relevant model, config, or page setup related to the issue.
- Share error messages: If possible, paste the full error output or stack trace.
- Attach screenshots: Visuals often help us understand UI-related bugs or logic problems more quickly.
- Mention your setup: Let us know your PHP version, Laravel version, Filament version, and the version of this plugin.
The more details you provide, the faster and better we can help. Thank you!
Contributions are welcome! Please follow these guidelines:
- Fork the repository and create a feature branch
- Run
composer formatto apply code style (Laravel Pint) - Add tests for any new functionality (
composer test) - Ensure PHPStan passes (
composer analyse) - Submit a pull request with a clear description
The MIT License (MIT). See LICENSE for more information.









