yacoubalhaidari/organization-chart
A powerful and elegant Filament widget plugin for creating interactive organizational charts. Built on top of Highcharts, this package provides a fluent API for visualizing your company's hierarchy with style.
make:organization-chartcomposer require yacoubalhaidari/organization-chart
The package assets are automatically published during installation. If needed, you can republish them:
php artisan filament:assets
Use the artisan command to scaffold a new organization chart widget:
php artisan make:organization-chart CompanyOrgChart
This creates a ready-to-use widget at app/Filament/Widgets/CompanyOrgChartWidget.php.
Add the widget to your Filament Panel Provider (e.g., app/Providers/Filament/AdminPanelProvider.php):
use App\Filament\Widgets\CompanyOrgChartWidget;
public function panel(Panel $panel): Panel
{
return $panel
->widgets([
CompanyOrgChartWidget::class,
]);
}
That's it! 🎉 Visit your Filament dashboard to see your organization chart.
Generate a widget with pre-configured examples:
php artisan make:organization-chart MyCompany
This creates a widget with:
Alternatively, create a widget manually:
<?php
namespace App\Filament\Widgets;
use YacoubAlhaidari\OrganizationChart\OrganizationChartWidget;
use YacoubAlhaidari\OrganizationChart\OrganizationChartBuilder;
class CompanyOrgChart extends OrganizationChartWidget
{
protected string $view = 'organization-chart::widget-without-description';
public function mount(): void
{
$builder = OrganizationChartBuilder::make()
->title('Company Structure')
->height(700)
->inverted(true);
$builder->executiveLevel([
['CEO', 'CTO'],
['CEO', 'CFO'],
]);
$builder->executiveNodes([
[
'id' => 'CEO',
'title' => 'Chief Executive Officer',
'name' => 'Your Name',
'color' => '#6366f1',
],
[
'id' => 'CTO',
'title' => 'Chief Technology Officer',
'name' => 'Tech Director',
'color' => '#3b82f6',
],
[
'id' => 'CFO',
'title' => 'Chief Financial Officer',
'name' => 'Finance Director',
'color' => '#10b981',
],
]);
$this->builder($builder);
}
}
public function mount(): void
{
$builder = OrganizationChartBuilder::make()
->title('Our Company')
->height(600)
->inverted(true)
->executiveLevel([
['CEO', 'CTO'],
['CEO', 'CFO'],
['CEO', 'COO'],
])
->executiveNodes([
[
'id' => 'CEO',
'title' => 'Chief Executive Officer',
'name' => 'Sarah Johnson',
'image' => 'https://i.pravatar.cc/150?img=1',
'color' => '#6366f1',
],
[
'id' => 'CTO',
'title' => 'CTO',
'name' => 'Michael Chen',
'image' => 'https://i.pravatar.cc/150?img=2',
'color' => '#3b82f6',
],
[
'id' => 'CFO',
'title' => 'CFO',
'name' => 'Emily Davis',
'color' => '#10b981',
],
[
'id' => 'COO',
'title' => 'COO',
'name' => 'David Martinez',
'color' => '#f59e0b',
],
]);
$this->builder($builder);
}
public function mount(): void
{
$builder = OrganizationChartBuilder::make()
->title('Complete Organization')
->height(800)
// Executives
->executiveLevel([
['CEO', 'CTO'],
['CEO', 'VP Sales'],
])
->executiveNodes([
['id' => 'CEO', 'name' => 'CEO', 'title' => 'Chief Executive Officer'],
['id' => 'CTO', 'name' => 'CTO', 'color' => '#3b82f6'],
['id' => 'VP Sales', 'name' => 'VP Sales', 'color' => '#10b981'],
])
// Departments
->departments([
['CTO', 'Engineering Dept'],
['CTO', 'Product Dept'],
['VP Sales', 'Sales Dept'],
])
->departmentNodes([
['id' => 'Engineering Dept', 'name' => 'Engineering'],
['id' => 'Product Dept', 'name' => 'Product'],
['id' => 'Sales Dept', 'name' => 'Sales'],
])
// Teams
->teams([
['Engineering Dept', 'Frontend Team'],
['Engineering Dept', 'Backend Team'],
])
->teamNodes([
['id' => 'Frontend Team', 'name' => 'Frontend'],
['id' => 'Backend Team', 'name' => 'Backend'],
]);
$this->builder($builder);
}
public function mount(): void
{
$executives = Employee::where('level', 'executive')
->with('manager')
->get();
$builder = OrganizationChartBuilder::make()
->title('Company Hierarchy')
->height(700)
->executiveLevel(
$executives->map(fn($e) => [
$e->manager?->name ?? 'Board',
$e->name
])->toArray()
)
->executiveNodes(
$executives->map(fn($e) => [
'id' => $e->name,
'title' => $e->job_title,
'name' => $e->full_name,
'image' => $e->avatar_url,
'color' => $e->department_color,
])->toArray()
);
$this->builder($builder);
}
public function mount(): void
{
$builder = OrganizationChartBuilder::make()
->title('Horizontal Organization')
->height(500)
->inverted(false) // Horizontal layout
->executiveLevel([
['Board', 'President'],
['President', 'VP Operations'],
['President', 'VP Marketing'],
])
->executiveNodes([
['id' => 'Board', 'name' => 'Board of Directors'],
['id' => 'President', 'name' => 'President'],
['id' => 'VP Operations', 'name' => 'VP Operations'],
['id' => 'VP Marketing', 'name' => 'VP Marketing'],
]);
$this->builder($builder);
}
| Command | Description | Example |
|---|---|---|
make:organization-chart |
Generate a new widget | php artisan make:organization-chart CompanyChart |
Command Usage:
# Create a widget named CompanyOrgChartWidget
php artisan make:organization-chart CompanyOrgChart
# Create a widget named TeamStructureWidget
php artisan make:organization-chart TeamStructure
# Widget suffix is added automatically
php artisan make:organization-chart Sales # Creates SalesWidget.php
| Method | Parameters | Default | Description |
|---|---|---|---|
title() |
string $title |
'Organization Chart' |
Set chart title |
height() |
int $pixels |
700 |
Set height in pixels |
inverted() |
bool $inverted |
true |
Vertical (true) or horizontal (false) |
Example:
$builder->title('My Company')
->height(800)
->inverted(true);
| Method | Description | Returns |
|---|---|---|
executiveLevel(array $relationships) |
Define top-level relationships | self |
departments(array $relationships) |
Define department relationships | self |
teams(array $relationships) |
Define team relationships | self |
Relationship Format: [['parentId', 'childId'], ...]
Example:
$builder->executiveLevel([
['CEO', 'CTO'],
['CEO', 'CFO'],
])
->departments([
['CTO', 'Engineering Dept'],
['CFO', 'Finance Dept'],
]);
| Method | Description | Level |
|---|---|---|
executiveNodes(array $nodes) |
Define executive details | Executive |
departmentNodes(array $nodes) |
Define department details | Department |
teamNodes(array $nodes) |
Define team details | Team |
nodes(array $nodes) |
Define all nodes at once | All |
Node Properties:
| Property | Type | Required | Description | Example |
|---|---|---|---|---|
id |
string |
✅ Yes | Unique identifier | 'CEO' |
name |
string |
✅ Yes | Display name | 'John Smith' |
title |
string |
No | Job title | 'Chief Executive Officer' |
image |
string |
No | Profile photo URL | 'https://example.com/photo.jpg' |
color |
string |
No | Hex color | '#3b82f6' |
column |
int |
No | Column position | 0, 1, 2 |
Example:
$builder->executiveNodes([
[
'id' => 'CEO',
'name' => 'John Smith',
'title' => 'Chief Executive Officer',
'image' => 'https://example.com/ceo.jpg',
'color' => '#6366f1',
],
]);
| Method | Returns | Description |
|---|---|---|
validate() |
array |
Check for errors |
getMissingNodes() |
array |
Get missing node IDs |
getAllRequiredIds() |
array |
Get all required IDs |
getSummary() |
array |
Get statistics |
Example:
$builder = OrganizationChartBuilder::make()
->executiveLevel([['CEO', 'CTO']])
->executiveNodes([
['id' => 'CEO', 'name' => 'CEO'],
]);
$validation = $builder->validate();
// Returns: ['valid' => false, 'errors' => ['Missing node: CTO']]
$missing = $builder->getMissingNodes();
// Returns: ['CTO']
Use the alternative view without description:
protected string $view = 'organization-chart::widget-without-description';
->executiveNodes([
['id' => 'CEO', 'name' => 'CEO', 'color' => '#6366f1'], // Indigo
['id' => 'CTO', 'name' => 'CTO', 'color' => '#3b82f6'], // Blue
['id' => 'CFO', 'name' => 'CFO', 'color' => '#10b981'], // Green
])
->executiveNodes([
[
'id' => 'CEO',
'name' => 'Sarah Johnson',
'image' => asset('storage/avatars/ceo.jpg'),
],
])
Publish and customize translation files:
php artisan vendor:publish --tag=organization-chart-translations
Edit in:
lang/vendor/organization-chart/en/widget.php (English)lang/vendor/organization-chart/ar/widget.php (Arabic)Control widget width:
class CompanyOrgChart extends OrganizationChartWidget
{
protected int | string | array $columnSpan = 'full'; // Full width
// Or specific spans:
// protected int | string | array $columnSpan = 2;
}
If you're contributing or want to build assets from source:
# Navigate to package directory
cd packages/organization-chart
# Install dependencies
npm install
# Build assets (production)
npm run build
# Or watch for changes (development)
npm run dev
| Command | Description |
|---|---|
npm run build |
Build CSS and JS for production |
npm run build:css |
Build CSS only |
npm run build:js |
Build JS only |
npm run dev |
Same as build (no watch mode) |
Publish the updated assets to your Filament application:
# From your Laravel project root
php artisan filament:assets
packages/organization-chart/
├── src/
│ ├── Commands/
│ │ └── MakeOrganizationChartCommand.php
│ ├── OrganizationChartServiceProvider.php
│ ├── OrganizationChartWidget.php
│ └── OrganizationChartBuilder.php
├── resources/
│ ├── js/
│ │ └── organization-chart.js # Source JavaScript
│ ├── css/
│ │ └── organization-chart.css # Source CSS
│ ├── dist/ # Compiled assets
│ │ ├── organization-chart.js
│ │ └── organization-chart.css
│ ├── views/
│ │ ├── widget.blade.php
│ │ └── widget-without-description.blade.php
│ └── lang/
│ ├── en/widget.php
│ └── ar/widget.php
├── composer.json
├── package.json
├── build.js # esbuild configuration
├── postcss.config.js # PostCSS configuration
└── README.md
Problem: Widget shows but chart is blank.
Solutions:
php artisan optimize:clearphp artisan filament:assetsProblem: Relationships reference undefined IDs.
Solution: Use validation to find issues:
$missing = $builder->getMissingNodes();
// Returns array of missing node IDs
Problem: Styles or JavaScript not working.
Solutions:
php artisan filament:assets --forcepublic/js/yacoubalhaidari/ and public/css/yacoubalhaidari/Contributions are welcome! Here's how you can help:
composer install && npm installnpm run buildPlease open an issue on GitHub with:
This package is open-sourced software licensed under the MIT License.
Yacoub Al-haidari
Built With:
If you find this package helpful, please consider:
Made with ❤️ for the Filament community
How can I help you explore Laravel packages today?