Brutalist

Raw. Functional. Unapologetic. Heavy borders, stark contrast, no rounded corners.

Technologies Demonstrated

[Alpine] Copy-to-clipboard with x-data + @click, state reset with setTimeout
[Alpine] Toggle demo — x-bind:class for conditional styling
[HTMX] hx-post form submission with hx-target + hx-swap
[Alpine] Collapsible card panels with x-show + x-transition

Color Palette

[Alpine]

Primary

#000000

Secondary

#FF0000

Accent

#FFFF00

BG

#FFFFFF

Surface

#F5F5F5

Muted

#555555

Click any swatch to copy hex value to clipboard.

<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-6 gap-4">
				@colorSwatch("Primary", "var(--color-primary)", "#000000")
				@colorSwatch("Secondary", "var(--color-secondary)", "#FF0000")
				@colorSwatch("Accent", "var(--color-accent)", "#FFFF00")
				@colorSwatch("BG", "var(--color-bg)", "#FFFFFF")
				@colorSwatch("Surface", "var(--color-surface)", "#F5F5F5")
				@colorSwatch("Muted", "var(--color-text-muted)", "#555555")
			</div>

Typography

Display — 3.5rem / Bold

BRUTALISM

Heading — 1.75rem / Bold

The Grid Is Your Canvas

Body — 1rem / Regular

Brutalist design strips away decoration to expose function. Every element serves a purpose. Nothing is hidden. Everything is raw.

Body Italic — 1rem / Italic

"Form ever follows function." — Louis Sullivan

Caption — 0.75rem / Regular

Figure 1. — Raw concrete texture, unfinished surfaces, exposed structure.

Spacing Scale

Base unit: 4px

4px
8px
16px
24px
32px
48px
64px

Buttons

[Alpine]

Sizes

Variants

Toggle Demo [Alpine]

State: OFF

<div x-data="{ active: false }" class="flex items-center gap-6">
						<button
							class="px-4 py-2 text-sm font-bold uppercase border-2 border-black font-mono cursor-pointer transition-all"
							x-bind:class="active ? 'bg-black text-white shadow-none translate-x-0 translate-y-0' : 'bg-white text-black brut-btn-secondary'"
							{ templ.Attributes{"@click": "active = !active"}... }
						>
							<span x-text="active ? 'ACTIVE' : 'INACTIVE'">INACTIVE</span>
						</button>
						<p class="text-xs font-mono text-gray-500" x-text="active ? 'State: ON' : 'State: OFF'">State: OFF</p>
					</div>

Forms

[HTMX] [Alpine]

Preferences

Weight

<form
					hx-post="/guides/brutalist/demo-form"
					hx-target="#form-response"
					hx-swap="innerHTML"
					hx-indicator="#brut-submit"
					class="space-y-6"
				>
					<!-- Text input -->
					<div>
						<label class="block text-xs font-bold uppercase mb-1 font-mono" for="brut-name">Name</label>
						<input
							id="brut-name"
							name="name"
							type="text"
							placeholder="Enter your name..."
							class="brut-input w-full px-3 py-2 text-sm font-mono"
						/>
					</div>
					<!-- Select -->
					<div>
						<label class="block text-xs font-bold uppercase mb-1 font-mono" for="brut-select">Category</label>
						<select id="brut-select" name="category" class="brut-input w-full px-3 py-2 text-sm font-mono cursor-pointer">
							<option value="">-- Select --</option>
							<option value="architecture">Architecture</option>
							<option value="design">Design</option>
							<option value="engineering">Engineering</option>
						</select>
					</div>
					<!-- Checkboxes -->
					<div>
						<p class="text-xs font-bold uppercase mb-2 font-mono">Preferences</p>
						<div class="space-y-2">
							<label class="flex items-center gap-2 cursor-pointer text-sm font-mono">
								<input type="checkbox" name="pref" value="raw" class="w-4 h-4 border-2 border-black rounded-none cursor-pointer"/>
								Raw aesthetic
							</label>
							<label class="flex items-center gap-2 cursor-pointer text-sm font-mono">
								<input type="checkbox" name="pref" value="functional" class="w-4 h-4 border-2 border-black rounded-none cursor-pointer"/>
								Function over form
							</label>
							<label class="flex items-center gap-2 cursor-pointer text-sm font-mono">
								<input type="checkbox" name="pref" value="honest" class="w-4 h-4 border-2 border-black rounded-none cursor-pointer"/>
								Honest materials
							</label>
						</div>
					</div>
					<!-- Radio buttons -->
					<div>
						<p class="text-xs font-bold uppercase mb-2 font-mono">Weight</p>
						<div class="space-y-2">
							<label class="flex items-center gap-2 cursor-pointer text-sm font-mono">
								<input type="radio" name="weight" value="light" class="w-4 h-4 border-2 border-black cursor-pointer"/>
								Light
							</label>
							<label class="flex items-center gap-2 cursor-pointer text-sm font-mono">
								<input type="radio" name="weight" value="regular" checked class="w-4 h-4 border-2 border-black cursor-pointer"/>
								Regular
							</label>
							<label class="flex items-center gap-2 cursor-pointer text-sm font-mono">
								<input type="radio" name="weight" value="bold" class="w-4 h-4 border-2 border-black cursor-pointer"/>
								Bold
							</label>
						</div>
					</div>
					<!-- Submit -->
					<div>
						<button type="submit" class="brut-btn-primary px-6 py-2 text-sm font-bold uppercase cursor-pointer"id="brut-submit">
							Submit Form
							<span class="brut-indicator font-mono"> ...</span>
						</button>
					</div>
				</form>

Cards & Panels

[Alpine]

Basic Card

STATIC

A standard content container. Hard borders, flat shadow, zero radius. No decoration. Pure structure.

Expandable Panel

+

Hidden content revealed on expand. Alpine.js powers the toggle with no server round-trip needed.

// Raw data block

status: EXPANDED

type: brutalist

border-radius: 0px

<div class="brut-card" x-data="{ expanded: false }">
					<div
						class="p-6 cursor-pointer flex items-center justify-between"
						{ templ.Attributes{"@click": "expanded = !expanded"}... }
					>
						<h3 class="text-base font-bold uppercase font-mono">Expandable Panel</h3>
						<span class="text-xl font-bold font-mono transition-transform" { templ.Attributes{":class": "expanded ? 'rotate-45' : ''"}... }>+</span>
					</div>
					<div x-show="expanded" class="px-6 pb-6 border-t-2 border-black">
						<p class="text-sm font-mono text-gray-600 pt-4">
							Hidden content revealed on expand. Alpine.js powers the toggle
							with no server round-trip needed.
						</p>
						<div class="mt-4 bg-black text-white p-3 font-mono text-xs">
							<p>{ "// Raw data block" }</p>
							<p>status: EXPANDED</p>
							<p>type: brutalist</p>
							<p>border-radius: 0px</p>
						</div>
					</div>
				</div>
!

Warning Panel

This is an alert/notice panel using the accent color. Hard edges. Cannot be ignored.

Tabs

[Alpine]

Design is not decoration. Design is function made visible. Every pixel, every border, every shadow must justify its existence.

Code is structure. Like brutalist architecture, the structure is not hidden behind a facade — it is the facade. What you see is what it does.

Documentation is honest. It does not promise what it cannot deliver. It does not hide complexity behind friendly language.

<div x-data="{ tab: 'design' }">
				<div class="flex" style="border-bottom: 2px solid var(--color-primary);">
					for _, t := range []struct{ id, label string }{
						{"design", "DESIGN"},
						{"code", "CODE"},
						{"docs", "DOCS"},
					} {
						<button
							class="brut-tab"
							{ templ.Attributes{
								":class": "tab==='" + t.id + "' ? 'brut-tab brut-tab-active' : 'brut-tab'",
								"@click": "tab='" + t.id + "'",
							}... }
						>{ t.label }</button>
					}
				</div>
				<div class="brut-card p-6" style="border-top: none;">
					<div x-show="tab==='design'">
						<p class="text-sm font-mono">Design is not decoration. Design is function made visible. Every pixel, every border, every shadow must justify its existence.</p>
					</div>
					<div x-show="tab==='code'" style="display: none;">
						<p class="text-sm font-mono">Code is structure. Like brutalist architecture, the structure is not hidden behind a facade — it is the facade. What you see is what it does.</p>
					</div>
					<div x-show="tab==='docs'" style="display: none;">
						<p class="text-sm font-mono">Documentation is honest. It does not promise what it cannot deliver. It does not hide complexity behind friendly language.</p>
					</div>
				</div>
			</div>