Cluster & Filler — Layout Primitives
Cluster and Filler are the primary layout primitives in this design system. They replace Cards, justify-between, and any opaque wrapper pattern.
Core Rules
- Clusters are always transparent — they never render a background. The
bgprop sets a CSS variable (--cluster-bg) that direct children inherit via a zero-specificity@layer baserule. - Every direct child of a Cluster must be a solid element — it should have its own visual identity (background color, etc.). Never place bare text or icons as direct Cluster children.
- No borders, no rounded corners — borders are almost never used in this design system. The only exception is the outline button variant. The theme radius is
0rem— never addrounded-*classes to layout elements. Clusters, Fillers, inputs, and all layout elements rely on background color contrast and spacing for visual separation, not border lines or rounded shapes. Never addborderorrounded-*to Cluster children, Fillers, or layout wrappers. - Use
<Filler />for space distribution — never usejustify-between,justify-end, orjustify-around. Filler is an invisibleflex-1spacer witharia-hidden="true". - Children can override the inherited bg — since the inheritance rule uses
:where()(zero specificity) inside@layer base, anybg-*utility on a child wins naturally.
Import
import { Cluster, Filler } from '@/components/ui/cluster'
Cluster Props
| Prop | Values | Default | Notes |
|---|---|---|---|
display |
'flex', 'inline-flex' |
'flex' |
|
direction |
'row', 'col' |
'row' |
|
align |
'start', 'center', 'end', 'stretch', 'baseline' |
'center' |
|
wrap |
true, false |
false |
|
bg |
'muted', 'accent' |
'muted' |
Sets --cluster-bg, inherited by children |
asChild |
boolean |
false |
Render as child element via Radix Slot |
Filler
Takes no special props. Renders a <div> with flex-1 min-w-0 self-stretch. It inherits --cluster-bg like any other child.
Filler omits role and aria-hidden from its props type since those are hardcoded (role="presentation", aria-hidden="true").
Patterns
Row with Filler (replaces justify-between)
<Cluster>
<div className="px-3 py-2">
<span className="text-sm font-medium">Label</span>
</div>
<Filler />
<Badge variant="accent">Status</Badge>
</Cluster>
Column layout (replaces Card)
<Cluster direction="col" align="stretch" bg="muted">
<div className="p-3">
<span className="text-sm font-medium">Header</span>
<p className="text-muted-foreground text-sm">Description</p>
</div>
<div className="p-3">
<Input placeholder="Field" />
</div>
<Cluster bg="muted">
<Filler />
<Button variant="secondary">Cancel</Button>
<Button>Create</Button>
</Cluster>
</Cluster>
Input-like solid child (sidebar search pattern)
<div className="bg-muted focus-within:bg-accent/70 flex h-10 items-center gap-3 px-3">
<SearchIcon className="text-muted-foreground size-4 shrink-0" />
<input
type="text"
placeholder="Search"
className="text-foreground placeholder:text-muted-foreground min-w-0 flex-1 bg-transparent font-mono text-sm tracking-wide uppercase outline-none"
/>
<Kbd className="h-[2em] px-2">⌘K</Kbd>
</div>
This is a valid Cluster child — it's a solid block with bg-muted and its own internal layout.
Inline display
For inline contexts, use asChild with a <span> to avoid <div> nesting issues:
<Cluster display="inline-flex" asChild>
<span>
<Badge>Active</Badge>
<Badge variant="muted">3 tasks</Badge>
</span>
</Cluster>
Overriding child background
<Cluster>
<div className="px-3 py-2">Inherits bg-muted</div>
<div className="bg-fd-background px-3 py-2">Overrides to different bg</div>
</Cluster>
Nested Clusters
Inner Clusters set their own --cluster-bg scope:
<Cluster direction="col" align="stretch" bg="muted">
<div className="p-3">Top section</div>
<Cluster bg="accent">
<Filler />
<Button>Action</Button>
</Cluster>
</Cluster>
Anti-patterns — DO NOT
// WRONG: bare text as direct child
<Cluster>
<span>Label</span>
<Filler />
</Cluster>
// WRONG: justify-between instead of Filler
<Cluster className="justify-between">
<div>Left</div>
<div>Right</div>
</Cluster>
// WRONG: Card wrapper with bg + padding
<div className="bg-card p-6">
<div>Content</div>
</div>
// WRONG: using borders for visual separation
<Cluster>
<div className="border px-3 py-2">Content</div>
</Cluster>
// WRONG: using rounded corners (theme radius is 0rem)
<Cluster>
<div className="rounded-md px-3 py-2">Content</div>
</Cluster>
// CORRECT alternatives:
<Cluster>
<div className="px-3 py-2">
<span>Label</span>
</div>
<Filler />
</Cluster>
CSS Dependency
Cluster requires this base CSS rule (injected automatically via the shadcn registry):
@layer base {
:where([data-slot='cluster'] > *) {
background-color: var(--cluster-bg, transparent);
}
}
And the --gap spacing token:
:root {
--gap: 0.25rem;
}
@theme inline {
--spacing-gap: var(--gap);
}