Patterns
Compositions built from the components. These are illustrative, not part of the system - nothing here introduces a class of its own.
Examples
Content list
Card, Mark and the layout primitives together. This is the shape softkiwi.games uses for its games list, and it is the reason the Card component itself is deliberately free of any game-specific structure.
Our games
Kiwi Kart
Racing
Four players, one couch, no loading screens.
Orchard
Puzzle
Grow something out of almost nothing.
Night Shift
Roguelike
The vending machine is not your friend.
Show markup
<div class="sk-flex sk-flex-col sk-gap-4">
<h2>
Our
<span class="sk-mark">
games
</span>
</h2>
<div class="sk-flex sk-flex-col sk-gap-3">
<div class="sk-card">
<div class="sk-card-body">
<div class="sk-flex sk-flex-col sk-gap-1">
<h3 class="sk-card-title">
Kiwi Kart
</h3>
<p class="sk-card-subtitle">
Racing
</p>
<p>
Four players, one couch, no loading screens.
</p>
</div>
</div>
</div>
<div class="sk-card">
<div class="sk-card-body">
<div class="sk-flex sk-flex-col sk-gap-1">
<h3 class="sk-card-title">
Orchard
</h3>
<p class="sk-card-subtitle">
Puzzle
</p>
<p>
Grow something out of almost nothing.
</p>
</div>
</div>
</div>
<div class="sk-card">
<div class="sk-card-body">
<div class="sk-flex sk-flex-col sk-gap-1">
<h3 class="sk-card-title">
Night Shift
</h3>
<p class="sk-card-subtitle">
Roguelike
</p>
<p>
The vending machine is not your friend.
</p>
</div>
</div>
</div>
</div>
</div>Signup card
An input group inside a card. The button is attached to the control rather than sitting in a row beside the field, so nothing has to be aligned by hand.
Stay in touch
Occasional mail about what we are building. No spam.
Show markup
<div class="sk-card" data-elevated="true">
<div class="sk-card-body">
<div class="sk-flex sk-flex-col sk-gap-3">
<h3 class="sk-card-title">
Stay in touch
</h3>
<p>
Occasional mail about what we are building. No spam.
</p>
<div class="sk-field">
<label class="sk-label" for="pattern-email">
Email
</label>
<div class="sk-input-group">
<input class="sk-input" id="pattern-email" name="pattern-email" type="email" value="" placeholder="you@example.com" data-size="md" aria-invalid="false">
<button class="sk-button" type="submit" data-variant="solid" data-size="md">
Sign up
</button>
</div>
</div>
</div>
</div>
</div>Settings form
The real test of a spacing scale: mixed control types, a checkbox, and an action row.
Show markup
<form>
<div class="sk-flex sk-flex-col sk-gap-5">
<div class="sk-field">
<label class="sk-label" for="pattern-name">
Name
<span class="sk-required" aria-hidden="true">
*
</span>
</label>
<input class="sk-input" id="pattern-name" name="pattern-name" type="text" value="" autocomplete="name" data-size="md" aria-invalid="false" required>
</div>
<div class="sk-field">
<label class="sk-label" for="pattern-contact">
Email
<span class="sk-required" aria-hidden="true">
*
</span>
</label>
<input class="sk-input" id="pattern-contact" name="pattern-contact" type="email" value="" autocomplete="email" data-size="md" aria-invalid="false" aria-describedby="pattern-contact-hint" required>
<p class="sk-hint" id="pattern-contact-hint">
We only use this to reply.
</p>
</div>
<div class="sk-field">
<label class="sk-label" for="pattern-visibility">
Visibility
</label>
<select class="sk-select" id="pattern-visibility" name="pattern-visibility" data-size="md" aria-invalid="false">
<option value="public">
Public
</option>
<option value="private" selected>
Private
</option>
</select>
</div>
<div class="sk-field">
<label class="sk-label" for="pattern-bio">
Bio
</label>
<textarea class="sk-textarea" id="pattern-bio" name="pattern-bio" rows="4" aria-invalid="false">
</textarea>
</div>
<label class="sk-check" for="pattern-terms">
<input id="pattern-terms" name="pattern-terms" type="checkbox" value="">
<span class="sk-check-label">
I have read the privacy policy
</span>
</label>
<div class="sk-button-group" role="group" data-attached="false">
<button class="sk-button" type="submit" data-variant="solid" data-size="md">
Save
</button>
<button class="sk-button" type="reset" data-variant="quiet" data-size="md">
Cancel
</button>
</div>
</div>
</form>Build pipeline
The dot doing what it was extracted for. Queued steps are hollow, the running step spins, finished steps take their status colour - and every row still says its state in words, because the vivid greens and ambers do not clear 3:1 on white.
Build 412
main - pushed 4 minutes ago
Show markup
<div class="sk-card">
<div class="sk-card-header">
<div class="sk-flex sk-flex-col sk-gap-1">
<h3 class="sk-card-title">
Build 412
</h3>
<p class="sk-card-subtitle">
main - pushed 4 minutes ago
</p>
</div>
<span class="sk-badge" data-status="info">
<svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<circle cx="12" cy="12" r="9">
</circle>
<path d="M12 11v5">
</path>
<path d="M12 8h.01">
</path>
</svg>
In progress
</span>
</div>
<div class="sk-card-body">
<div class="sk-flex sk-flex-col sk-gap-3">
<div class="sk-flex sk-items-center sk-gap-3">
<span class="sk-dot" data-status="success" data-size="lg">
<span class="sk-visually-hidden">
Passed
</span>
</span>
<span class="sk-flex-1 sk-min-w-0">
Checkout
</span>
<span class="sink-caption">
2s
</span>
</div>
<div class="sk-flex sk-items-center sk-gap-3">
<span class="sk-dot" data-status="success" data-size="lg">
<span class="sk-visually-hidden">
Passed
</span>
</span>
<span class="sk-flex-1 sk-min-w-0">
Install dependencies
</span>
<span class="sink-caption">
41s
</span>
</div>
<div class="sk-flex sk-items-center sk-gap-3">
<span class="sk-dot" data-status="success" data-size="lg">
<span class="sk-visually-hidden">
Passed
</span>
</span>
<span class="sk-flex-1 sk-min-w-0">
Vet and test
</span>
<span class="sink-caption">
1m 12s
</span>
</div>
<div class="sk-flex sk-items-center sk-gap-3">
<span class="sk-dot" data-status="warning" data-size="lg" data-busy="true" data-motion="essential">
<span class="sk-visually-hidden">
Running
</span>
</span>
<span class="sk-flex-1 sk-min-w-0">
Layout audit
</span>
<span class="sink-caption">
running
</span>
</div>
<div class="sk-flex sk-items-center sk-gap-3">
<span class="sk-dot" data-size="lg" data-hollow="true">
<span class="sk-visually-hidden">
Queued
</span>
</span>
<span class="sk-flex-1 sk-min-w-0">
Build image
</span>
</div>
<div class="sk-flex sk-items-center sk-gap-3">
<span class="sk-dot" data-size="lg" data-hollow="true">
<span class="sk-visually-hidden">
Queued
</span>
</span>
<span class="sk-flex-1 sk-min-w-0">
Deploy
</span>
</div>
</div>
</div>
<div class="sk-card-footer">
<div class="sk-progress-field">
<div class="sk-progress-head">
<span class="sk-progress-value">
3 of 6 steps
</span>
</div>
<progress class="sk-progress" value="3" max="6">
</progress>
</div>
</div>
</div>Toolbar
A button group and independent actions in one row, pushed apart with sk-justify-between.
Show markup
<div class="sk-flex sk-flex-wrap sk-items-center sk-justify-between sk-gap-3">
<div class="sk-button-group" role="group" aria-label="View">
<button class="sk-button" type="button" data-variant="neutral" data-size="md" aria-pressed="true">
Grid
</button>
<button class="sk-button" type="button" data-variant="neutral" data-size="md" aria-pressed="false">
List
</button>
</div>
<div class="sk-flex sk-items-center sk-gap-2">
<button class="sk-button" type="button" data-variant="quiet" data-size="sm">
Filter
</button>
<button class="sk-button" type="button" data-variant="solid" data-size="sm">
New
</button>
</div>
</div>