Skip to main content

Basic Usage

Learn how to create your first organizational chart or family tree in just 5 minutes!

๐Ÿš€ Quick Startโ€‹

Step 1: Import the Packageโ€‹

import 'package:org_chart/org_chart.dart';
import 'package:flutter/material.dart';

Step 2: Define Your Data Modelโ€‹

// Define your data model
class Employee {
final String id;
final String name;
final String? managerId;
final String position;
final String department;
final String imageUrl;

Employee({
required this.id,
required this.name,
this.managerId,
required this.position,
required this.department,
required this.imageUrl,
});
}

// Create sample data
final employees = [
Employee(
id: '1',
name: 'Jane Smith',
managerId: null,
position: 'CEO',
department: 'Executive',
imageUrl: 'https://i.pravatar.cc/150?img=1',
),
Employee(
id: '2',
name: 'John Doe',
managerId: '1',
position: 'CTO',
department: 'Technology',
imageUrl: 'https://i.pravatar.cc/150?img=2',
),
Employee(
id: '3',
name: 'Sarah Johnson',
managerId: '1',
position: 'CFO',
department: 'Finance',
imageUrl: 'https://i.pravatar.cc/150?img=3',
),
Employee(
id: '4',
name: 'Mike Wilson',
managerId: '2',
position: 'Lead Developer',
department: 'Technology',
imageUrl: 'https://i.pravatar.cc/150?img=4',
),
Employee(
id: '5',
name: 'Emily Brown',
managerId: '2',
position: 'QA Manager',
department: 'Technology',
imageUrl: 'https://i.pravatar.cc/150?img=5',
),
];

Step 3: Create the Controllerโ€‹

class MyOrgChartScreen extends StatefulWidget {

_MyOrgChartScreenState createState() => _MyOrgChartScreenState();
}

class _MyOrgChartScreenState extends State<MyOrgChartScreen> {
late OrgChartController<Employee> controller;


void initState() {
super.initState();

// Initialize the controller
controller = OrgChartController<Employee>(
items: employees,

// Required: Provide unique ID for each item
idProvider: (employee) => employee.id,

// Required: Provide parent ID (manager for org chart)
toProvider: (employee) => employee.managerId,

// Optional: Update parent when reorganizing
toSetter: (employee, newManagerId) => Employee(
id: employee.id,
name: employee.name,
managerId: newManagerId,
position: employee.position,
department: employee.department,
imageUrl: employee.imageUrl,
),

// Optional: Customize box size
boxSize: Size(220, 120),

// Optional: Customize spacing
spacing: 40,
runSpacing: 80,

// Optional: Set orientation
orientation: GraphOrientation.topToBottom,

// Optional: Arrange leaf nodes in columns
leafColumns: 3,
);
}


Widget build(BuildContext context) {
// Continue to Step 4...
}
}

Step 4: Build the Chart Widgetโ€‹


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Company Organization'),
actions: [
IconButton(
icon: Icon(Icons.swap_horiz),
onPressed: () {
// Switch orientation
controller.switchOrientation();
},
),
],
),
body: OrgChart<Employee>(
controller: controller,

// Build each node
builder: (NodeBuilderDetails<Employee> details) {
return Card(
elevation: details.isBeingDragged ? 8 : 4,
color: details.level == 1
? Colors.blue.shade100
: Colors.white,
child: Container(
padding: EdgeInsets.all(12),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Employee photo
CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(details.item.imageUrl),
),
SizedBox(height: 8),

// Name
Text(
details.item.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),

// Position
Text(
details.item.position,
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),

// Department badge
Container(
margin: EdgeInsets.only(top: 4),
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(10),
),
child: Text(
details.item.department,
style: TextStyle(fontSize: 10),
),
),

// Expand/Collapse button if has children
if (hasSubordinates(details.item))
IconButton(
icon: Icon(
details.nodesHidden
? Icons.expand_more
: Icons.expand_less,
size: 20,
),
onPressed: () {
details.hideNodes();
},
),
],
),
),
);
},

// Optional: Enable drag and drop
isDraggable: true,

// Optional: Handle drop events
onDrop: (draggedEmployee, targetEmployee, isSubordinate) {
setState(() {
// Update your data model
updateEmployeeManager(
draggedEmployee,
targetEmployee,
);

// Refresh the chart
controller.replaceAll(updatedEmployees);
});
},

// Optional: Customize animations
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,

// Optional: Customize edge appearance
linePaint: Paint()
..color = Colors.grey.shade400
..strokeWidth = 2.0,
arrowStyle: SolidGraphArrow(),
cornerRadius: 10,
lineEndingType: LineEndingType.arrow,
),
);
}

// Helper method to check if employee has subordinates
bool hasSubordinates(Employee employee) {
return employees.any((e) => e.managerId == employee.id);
}

๐ŸŽจ Complete Working Exampleโ€‹

Here's a complete, runnable example you can copy and paste:

main.dart
import 'package:flutter/material.dart';
import 'package:org_chart/org_chart.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
title: 'Org Chart Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: BasicOrgChartDemo(),
);
}
}

class BasicOrgChartDemo extends StatefulWidget {

_BasicOrgChartDemoState createState() => _BasicOrgChartDemoState();
}

class _BasicOrgChartDemoState extends State<BasicOrgChartDemo> {
late OrgChartController<Map<String, dynamic>> controller;

final List<Map<String, dynamic>> employees = [
{'id': '1', 'name': 'Jane CEO', 'title': 'Chief Executive', 'managerId': null},
{'id': '2', 'name': 'John CTO', 'title': 'Chief Technology', 'managerId': '1'},
{'id': '3', 'name': 'Sarah CFO', 'title': 'Chief Finance', 'managerId': '1'},
{'id': '4', 'name': 'Mike Dev', 'title': 'Lead Developer', 'managerId': '2'},
{'id': '5', 'name': 'Emily QA', 'title': 'QA Manager', 'managerId': '2'},
{'id': '6', 'name': 'Tom Jr Dev', 'title': 'Junior Developer', 'managerId': '4'},
{'id': '7', 'name': 'Lisa Analyst', 'title': 'Financial Analyst', 'managerId': '3'},
];


void initState() {
super.initState();
controller = OrgChartController(
items: employees,
idProvider: (item) => item['id'],
toProvider: (item) => item['managerId'],
boxSize: Size(180, 100),
spacing: 30,
runSpacing: 60,
);
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Organization Chart'),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.rotate_90_degrees_ccw),
tooltip: 'Switch Orientation',
onPressed: () => controller.switchOrientation(),
),
],
),
body: OrgChart<Map<String, dynamic>>(
controller: controller,
builder: (details) {
final item = details.item;
return Card(
elevation: details.isBeingDragged ? 8 : 3,
color: details.level == 1
? Theme.of(context).primaryColor.withOpacity(0.1)
: Colors.white,
child: Container(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.person,
size: 30,
color: Theme.of(context).primaryColor,
),
SizedBox(height: 8),
Text(
item['name'],
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
Text(
item['title'],
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
);
},
isDraggable: true,
linePaint: Paint()
..color = Colors.grey.shade400
..strokeWidth = 2.0,
arrowStyle: SolidGraphArrow(),
cornerRadius: 10,
),
);
}
}

๐ŸŽฏ What's Next?โ€‹

Congratulations! You've created your first chart. Now explore more advanced features:


๐Ÿ’ก Pro Tip: Start simple with basic nodes, then gradually add features like drag & drop, animations, and custom styling as you become more comfortable with the API.