Selects from hierarchical data.
<div class="ts" style="--accent:#D9C8F0;border-radius:8px;">
<div class="ts__label" id="ts-label">Office location</div>
<ul class="ts__tree ts__tree--london" role="tree" aria-labelledby="ts-label">
<li class="ts__branch" role="treeitem" aria-expanded="true">
<span class="ts__branch-label">United Kingdom</span>
<ul class="ts__group" role="group">
<li id="ts-london" class="ts__leaf" role="treeitem" aria-selected="true">London</li>
<li id="ts-manchester" class="ts__leaf" role="treeitem" aria-selected="false">Manchester</li>
</ul>
</li>
<li class="ts__branch" role="treeitem" aria-expanded="true">
<span class="ts__branch-label">France</span>
<ul class="ts__group" role="group">
<li id="ts-paris" class="ts__leaf" role="treeitem" aria-selected="false">Paris</li>
</ul>
</li>
</ul>
</div>
<style>
.ts { font: 14px system-ui, sans-serif; color: #241430; max-width: 260px; background: #FAF7F2; border: 1.5px solid #24143020; padding: 12px; box-sizing: border-box; }
.ts__label { font-weight: 500; margin-bottom: 8px; }
.ts__tree, .ts__group { list-style: none; margin: 0; padding: 0; }
.ts__group { padding-left: 18px; }
.ts__branch { margin-bottom: 4px; }
.ts__branch-label { display: block; padding: 6px 8px; border-radius: 6px; font-weight: 500; cursor: pointer; }
.ts__branch-label:hover { background: #24143014; }
.ts__branch[aria-expanded="false"] .ts__group { display: none; }
.ts__tree--collapsed .ts__group { display: none; }
.ts__leaf { padding: 6px 8px; border-radius: 6px; cursor: pointer; }
.ts__leaf:hover { background: #24143014; }
.ts__tree--london #ts-london, .ts__tree--manchester #ts-manchester, .ts__tree--paris #ts-paris { background: var(--accent); font-weight: 600; }
</style><div class="ts-tw ts-tw--london font-sans text-sm text-[#241430] max-w-[260px] bg-[#FAF7F2] border-[1.5px] border-[#24143020] p-3 box-border" style="border-radius:8px;">
<div class="font-medium mb-2" id="ts-tw-label">Office location</div>
<ul class="list-none m-0 p-0" role="tree" aria-labelledby="ts-tw-label">
<li class="mb-1" role="treeitem" aria-expanded="true">
<span class="block px-2 py-1.5 rounded-md font-medium cursor-pointer hover:bg-[#24143014]">United Kingdom</span>
<ul class="ts-tw-group list-none m-0 pl-[18px]" role="group">
<li id="ts-tw-london" class="px-2 py-1.5 rounded-md cursor-pointer hover:bg-[#24143014]" role="treeitem" aria-selected="true">London</li>
<li id="ts-tw-manchester" class="px-2 py-1.5 rounded-md cursor-pointer hover:bg-[#24143014]" role="treeitem" aria-selected="false">Manchester</li>
</ul>
</li>
<li class="mb-1" role="treeitem" aria-expanded="true">
<span class="block px-2 py-1.5 rounded-md font-medium cursor-pointer hover:bg-[#24143014]">France</span>
<ul class="ts-tw-group list-none m-0 pl-[18px]" role="group">
<li id="ts-tw-paris" class="px-2 py-1.5 rounded-md cursor-pointer hover:bg-[#24143014]" role="treeitem" aria-selected="false">Paris</li>
</ul>
</li>
</ul>
</div>
<style>
.ts-tw--london #ts-tw-london, .ts-tw--manchester #ts-tw-manchester, .ts-tw--paris #ts-tw-paris { background: #D9C8F0; font-weight: 600; }
li[aria-expanded="false"] > .ts-tw-group { display: none; }
</style>export function TreeSelect({
label = "Office location",
node = "london",
expanded = true,
accent = "#D9C8F0",
radius = 8,
}) {
const branches = [
{ name: "United Kingdom", children: [{ id: "london", name: "London" }, { id: "manchester", name: "Manchester" }] },
{ name: "France", children: [{ id: "paris", name: "Paris" }] },
];
const leafStyle = (id) => ({
padding: "6px 8px", borderRadius: 6, cursor: "pointer",
background: id === node ? accent : "transparent",
fontWeight: id === node ? 600 : 400,
});
return (
<div style={{ fontFamily: "system-ui, sans-serif", fontSize: 14, color: "#241430", maxWidth: 260, background: "#FAF7F2", border: "1.5px solid #24143020", padding: 12, boxSizing: "border-box", borderRadius: radius }}>
<div id="ts-r-label" style={{ fontWeight: 500, marginBottom: 8 }}>{label}</div>
<ul style={{ listStyle: "none", margin: 0, padding: 0 }} role="tree" aria-labelledby="ts-r-label">
{branches.map((branch) => (
<li key={branch.name} style={{ marginBottom: 4 }} role="treeitem" aria-expanded={expanded}>
<span style={{ display: "block", padding: "6px 8px", borderRadius: 6, fontWeight: 500, cursor: "pointer" }}>{branch.name}</span>
{expanded && (
<ul style={{ listStyle: "none", margin: 0, paddingLeft: 18 }} role="group">
{branch.children.map((leaf) => (
<li key={leaf.id} role="treeitem" aria-selected={leaf.id === node} style={leafStyle(leaf.id)}>{leaf.name}</li>
))}
</ul>
)}
</li>
))}
</ul>
</div>
);
}