Composition
Build loud. Compose smart.
v0.2.0 introduces a composition system for building loud, token-driven, Angular-first brutalist UIs. Small primitives that lock together like LEGO — each primitive owns one job, and they compose to build anything.
The mental model
Every ng-brutalism UI starts with a surface. Regions inside that surface are sections. Content flows vertically in stacks and horizontally in clusters. Two-column layouts use split. Actions and metadata complete the picture.
Decision guide
Rendered example
A complete panel built with composition primitives only — no class soup required.
Launch checklist
Build a loud release panel using composition primitives instead of class-heavy wrappers.
Before / after
The same brutalist card — one written with raw Tailwind classes, one with composition primitives.
Before — class soup
<div
class="rounded-2xl border-4 border-black
bg-yellow-300 p-6
shadow-[8px_8px_0_#000]"
>
<div
class="flex items-center justify-between
border-b-4 border-black pb-4"
>
<h2>Launch card</h2>
<span>v0.2.0</span>
</div>
<div class="py-4">
<p>Lots of repeated class decisions.</p>
</div>
</div>After — composition
<article nbSurface tone="yellow" radius="xl"
shadow="hard" clip>
<header nbSection padding="lg" divider="bottom"
layout="between" align="center">
<h2 nbTitle>Launch card</h2>
<span nbChip tone="pink">v0.2.0</span>
</header>
<div nbSection padding="lg">
<p nbText>Same structure, clearer composition.</p>
</div>
</article>Less class soup. More composition.
API language
Every primitive in ng-brutalism speaks the same token vocabulary. Learn it once, use it everywhere.
toneVisual intent / color theme
sizeComponent scale
radiusCorner shape
shadowBrutalist offset depth
borderOutline strength
paddingInternal space
gapChild spacing
alignCross-axis alignment
justifyMain-axis alignment
collapseResponsive layout behavior
clipKeep inner regions inside the outer radius
dividerBorder between regions — top, bottom, etc.
Customization
Use public inputs first. Reach for CSS custom properties when presets are not enough. Keep overrides local so they only affect the element and its descendants.
<!-- Step 1: use public inputs first -->
<div nbSurface tone="cream" radius="xl" shadow="hard">
Token-driven surface
</div>
<!-- Step 2: CSS variables for fine-grained control -->
<div
nbSurface
tone="cream"
style="--nb-surface-bg: #faf6f0"
>
Custom surface background
</div>
<!-- Overrides are local — only this element is affected -->
<div
nbSurface
style="--nb-shadow-offset-x: 12px; --nb-shadow-offset-y: 12px"
>
Custom shadow offset
</div>