Minimal

Calm. Spacious. Nothing extra. Design through restraint and generous whitespace.


Technologies Demonstrated

[Alpine] Copy-to-clipboard with navigator.clipboard.writeText
[HTMX] hx-post form submission with hx-target response swap
[Alpine] x-show card expand with smooth x-transition

Color Palette

[Alpine]

Primary

#1a1a1a

Secondary

#6b7280

Accent

#3b82f6

Background

#fafafa

Surface

#ffffff

Muted

#9ca3af

Click any swatch to copy the hex value to clipboard.

<div class="grid grid-cols-2 sm:grid-cols-3 gap-4">
				@minColorSwatch("Primary", "var(--color-primary)", "#1a1a1a")
				@minColorSwatch("Secondary", "var(--color-secondary)", "#6b7280")
				@minColorSwatch("Accent", "var(--color-accent)", "#3b82f6")
				@minColorSwatch("Background", "var(--color-bg)", "#fafafa")
				@minColorSwatch("Surface", "var(--color-surface)", "#ffffff")
				@minColorSwatch("Muted", "var(--color-text-muted)", "#9ca3af")
			</div>

Typography

Display — 3rem / Light

Simplicity

Heading — 1.5rem / Semibold

Clear hierarchy guides the eye

Body — 1rem / Regular

Minimal design is not about removing things arbitrarily — it's about keeping only what serves a purpose. Every element earns its place.

Body / Medium weight

"Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away."

Caption — 0.8rem / Regular

Figure 1. — Whitespace is not empty space; it is a deliberate design element.

Spacing Scale

Base unit: 4px

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

Buttons

[Alpine]

Sizes

Variants

Toggle Demo [Alpine]

State: off

Forms

[HTMX] [Alpine]

Preferences

Weight

<form
					hx-post="/guides/minimal/demo-form"
					hx-target="#min-form-response"
					hx-swap="innerHTML"
					class="space-y-6"
				>
					<!-- Text input -->
					<div>
						<label class="block text-sm font-medium mb-1.5" style="color: var(--color-primary);" for="min-name">Name</label>
						<input
							id="min-name"
							name="name"
							type="text"
							placeholder="Your name"
							class="min-input w-full px-4 py-2.5 text-sm"
						/>
					</div>
					<!-- Select -->
					<div>
						<label class="block text-sm font-medium mb-1.5" style="color: var(--color-primary);" for="min-select">Category</label>
						<select id="min-select" name="category" class="min-input w-full px-4 py-2.5 text-sm cursor-pointer">
							<option value="">Select one…</option>
							<option value="clarity">Clarity</option>
							<option value="balance">Balance</option>
							<option value="restraint">Restraint</option>
						</select>
					</div>
					<!-- Checkboxes -->
					<div>
						<p class="text-sm font-medium mb-3" style="color: var(--color-primary);">Preferences</p>
						<div class="space-y-2.5">
							<label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);">
								<input type="checkbox" name="pref" value="whitespace" class="w-4 h-4 cursor-pointer accent-blue-500"/>
								Generous whitespace
							</label>
							<label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);">
								<input type="checkbox" name="pref" value="typography" class="w-4 h-4 cursor-pointer accent-blue-500"/>
								Strong typography
							</label>
							<label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);">
								<input type="checkbox" name="pref" value="subtle" class="w-4 h-4 cursor-pointer accent-blue-500"/>
								Subtle interactions
							</label>
						</div>
					</div>
					<!-- Radio buttons -->
					<div>
						<p class="text-sm font-medium mb-3" style="color: var(--color-primary);">Weight</p>
						<div class="space-y-2.5">
							<label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);">
								<input type="radio" name="weight" value="light" class="w-4 h-4 cursor-pointer accent-blue-500"/>
								Light
							</label>
							<label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);">
								<input type="radio" name="weight" value="regular" checked class="w-4 h-4 cursor-pointer accent-blue-500"/>
								Regular
							</label>
							<label class="flex items-center gap-3 cursor-pointer text-sm" style="color: var(--color-text);">
								<input type="radio" name="weight" value="medium" class="w-4 h-4 cursor-pointer accent-blue-500"/>
								Medium
							</label>
						</div>
					</div>
					<!-- Textarea -->
					<div>
						<label class="block text-sm font-medium mb-1.5" style="color: var(--color-primary);" for="min-message">Message</label>
						<textarea
							id="min-message"
							name="message"
							placeholder="Tell us more..."
							rows="3"
							class="min-input w-full px-4 py-2.5 text-sm"
						></textarea>
					</div>
					<!-- Submit -->
					<div class="pt-2">
						<button type="submit" class="min-btn-primary px-6 py-2.5 text-sm cursor-pointer">
							Submit
						</button>
					</div>
				</form>

Cards & Panels

[Alpine]

Basic Card

Static

A clean content container with soft shadow, rounded corners, and a single-pixel border. Whitespace does the heavy lifting.


Expandable Panel

+

Revealed content with a smooth transition. Alpine handles the toggle with zero server round-trips.

// state snapshot

expanded: true

border-radius: 16px

shadow: subtle

<div class="min-card overflow-hidden" x-data="{ expanded: false }">
					<div
						class="px-6 py-5 flex items-center justify-between cursor-pointer"
						{ templ.Attributes{"@click": "expanded = !expanded"}... }
					>
						<h3 class="text-base font-semibold" style="color: var(--color-primary);">Expandable Panel</h3>
						<span
							class="text-lg font-light transition-transform duration-200"
							style="color: var(--color-text-muted);"
							{ templ.Attributes{":class": "expanded ? 'rotate-45' : ''"}... }
						>+</span>
					</div>
					<div x-show="expanded" x-transition style="border-top: var(--border-width) solid var(--border-color);">
						<div class="px-6 py-5">
							<p class="text-sm leading-relaxed mb-4" style="color: var(--color-secondary);">
								Revealed content with a smooth transition. Alpine handles the toggle with
								zero server round-trips.
							</p>
							<div class="rounded-lg p-4 text-sm" style="background: var(--color-bg); border: var(--border-width) solid var(--border-color); color: var(--color-text-muted);">
								<p>{ "// state snapshot" }</p>
								<p>expanded: true</p>
								<p>border-radius: 16px</p>
								<p>shadow: subtle</p>
							</div>
						</div>
					</div>
				</div>
i

Info Panel

Accent panels use a tinted background and matching border for a calm, informational tone — never alarming.

Design Principles

[HTMX]

This section loads via hx-trigger="revealed" — content is fetched only when scrolled into view.

Loading...

<div
				hx-get="/guides/minimal/principles"
				hx-trigger="revealed"
				hx-swap="innerHTML"
				class="min-card p-8"
			>
				<p class="text-sm" style="color: var(--color-text-muted);">Loading...</p>
			</div>