Tree chart
A tidy node-link tree, top-down or left to right, with parents centred over their children. Click a branch to collapse or expand it, or move through it with the keys of a tree view.
| Node | Value |
|---|---|
| Priya (CEO) | 11 people |
| Priya (CEO) > Marcus (CTO) | 5 people |
| Priya (CEO) > Marcus (CTO) > Lena | 3 people |
| Priya (CEO) > Marcus (CTO) > Lena > Tom | 1 people |
| Priya (CEO) > Marcus (CTO) > Lena > Aisha | 1 people |
| Priya (CEO) > Marcus (CTO) > Lena > Ravi | 1 people |
| Priya (CEO) > Marcus (CTO) > Diego | 2 people |
| Priya (CEO) > Marcus (CTO) > Diego > Mei | 1 people |
| Priya (CEO) > Marcus (CTO) > Diego > Sam | 1 people |
| Priya (CEO) > Hannah (CFO) | 2 people |
| Priya (CEO) > Hannah (CFO) > Oliver | 1 people |
| Priya (CEO) > Hannah (CFO) > Grace | 1 people |
| Priya (CEO) > Kofi (COO) | 4 people |
| Priya (CEO) > Kofi (COO) > Ines | 3 people |
| Priya (CEO) > Kofi (COO) > Ines > Yuki | 1 people |
| Priya (CEO) > Kofi (COO) > Ines > Ben | 1 people |
| Priya (CEO) > Kofi (COO) > Ines > Zara | 1 people |
| Priya (CEO) > Kofi (COO) > Noah | 1 people |
| Node | Value |
|---|---|
| Priya (CEO) | 11 |
| Priya (CEO) > Marcus (CTO) | 5 |
| Priya (CEO) > Marcus (CTO) > Lena | 3 |
| Priya (CEO) > Marcus (CTO) > Lena > Tom | 1 |
| Priya (CEO) > Marcus (CTO) > Lena > Aisha | 1 |
| Priya (CEO) > Marcus (CTO) > Lena > Ravi | 1 |
| Priya (CEO) > Marcus (CTO) > Diego | 2 |
| Priya (CEO) > Marcus (CTO) > Diego > Mei | 1 |
| Priya (CEO) > Marcus (CTO) > Diego > Sam | 1 |
| Priya (CEO) > Hannah (CFO) | 2 |
| Priya (CEO) > Hannah (CFO) > Oliver | 1 |
| Priya (CEO) > Hannah (CFO) > Grace | 1 |
| Priya (CEO) > Kofi (COO) | 4 |
| Priya (CEO) > Kofi (COO) > Ines | 3 |
| Priya (CEO) > Kofi (COO) > Ines > Yuki | 1 |
| Priya (CEO) > Kofi (COO) > Ines > Ben | 1 |
| Priya (CEO) > Kofi (COO) > Ines > Zara | 1 |
| Priya (CEO) > Kofi (COO) > Noah | 1 |
Usage
use hydroxy_leptos::tree_chart::*;
use leptos::prelude::*;
fn team(lead: &str, people: &[&str]) -> Tree {
Tree::branch(lead, people.iter().map(|p| Tree::leaf(*p, 1.0)).collect())
}
pub fn demo() -> AnyView {
// Reporting lines; each person counts as one, so a branch's value is its headcount.
let org = Tree::branch(
"Priya (CEO)",
vec![
Tree::branch("Marcus (CTO)", vec![team("Lena", &["Tom", "Aisha", "Ravi"]), team("Diego", &["Mei", "Sam"])]),
team("Hannah (CFO)", &["Oliver", "Grace"]),
Tree::branch("Kofi (COO)", vec![team("Ines", &["Yuki", "Ben", "Zara"]), Tree::leaf("Noah", 1.0)]),
],
);
view! {
<div style="display: grid; gap: var(--space-8);">
<TreeChart root=org.clone() label="Reporting lines" format=|v: f64| format!("{v:.0} people") />
<TreeChart root=org label="Reporting lines, left to right" orientation=Orientation::Horizontal height=420 />
</div>
}
.into_any()
}use dioxus::prelude::*;
use hydroxy_dioxus::tree_chart::{Orientation, Tree, TreeChart};
fn team(lead: &str, people: &[&str]) -> Tree {
Tree::branch(lead, people.iter().map(|p| Tree::leaf(*p, 1.0)).collect())
}
#[component]
pub fn TreeChartDemo() -> Element {
// Reporting lines; each person counts as one, so a branch's value is its headcount.
let org = Tree::branch(
"Priya (CEO)",
vec![
Tree::branch("Marcus (CTO)", vec![team("Lena", &["Tom", "Aisha", "Ravi"]), team("Diego", &["Mei", "Sam"])]),
team("Hannah (CFO)", &["Oliver", "Grace"]),
Tree::branch("Kofi (COO)", vec![team("Ines", &["Yuki", "Ben", "Zara"]), Tree::leaf("Noah", 1.0)]),
],
);
rsx! {
div { style: "display: grid; gap: var(--space-8);",
TreeChart { root: org.clone(), label: "Reporting lines", format: |v: f64| format!("{v:.0} people") }
TreeChart { root: org, label: "Reporting lines, left to right", orientation: Orientation::Horizontal, height: 420 }
}
}
}
Anatomy
| Component | data-part | Renders |
|---|---|---|
TreeChart | root | figure with `data-orientation` and a screen-reader table of every node |
| marks | Focusable SVG; arrow keys move through the tree |
| link | Curved line from a parent to a child |
| node | Dot and label; `data-collapsed`, `data-leaf`, `data-active` |
| tooltip | Name, value and how many children are shown or hidden |
| legend | Top-level branches when there are two or more |
Keyboard
| Key | Does |
|---|---|
Up / Down | Previous or next visible node |
Right | Expand a collapsed branch, else move to its first child |
Left | Collapse an open branch, else move to the parent |
Home / End | First or last visible node |
Enter / Space | Collapse or expand the focused branch |
Escape | Clear the focused node |
Props
| Prop | Type | Notes |
|---|---|---|
root | Tree | Required. Branch values come from their children |
label | String | Required. What the chart shows; the accessible name |
orientation | Orientation | Vertical (default, root at the top) or Horizontal (root on the left) |
height | u16 | Plot height in px at an 800px drawing width. Default 360 |
format | Fn(f64) -> String | Formats values in the tooltip and table |
Events
| Prop | Type | Notes |
|---|---|---|
on_hover | Callback<Option<Datum>> | The mark under the pointer or keyboard focus changes, or is left. Fires only on a change |
on_select | Callback<Datum> | Click, tap or Enter on a mark |