A little inspiration, occasionally.
Design notes, useful patterns, and new releases. A quiet corner of your inbox, with something worth opening.
Thoughtful defaults.
Beautifully simple.
Build clear, considered interfaces with the HTML you already know. One stylesheet, native components, and room for your own design.
Classless · CSS only · Light and dark · MIT licensed
Add the stylesheet to your page. Semantic elements get considered defaults; attributes give you variants when you need them.
<link rel="stylesheet" href="./berlinx.min.css" />
Download the stylesheet · Installation & theming guide
Light and dark themes follow the reader’s system setting. Add
theme="light" or theme="dark" to
<html> to choose one, or to any container to theme
just that region. Try the moon button to switch this page.
Design notes, useful patterns, and new releases. A quiet corner of your inbox, with something worth opening.
Good typography makes an interface feel effortless. A restrained scale, comfortable line lengths, and deliberate spacing help people find what matters and read without distraction.
The details should support the content. Give every element enough space to be understood, and every page a clear place to begin.
Bold
Italic
Underline
Deleted
Inserted
Strikethrough
Small
Text Sub
Text Sup
Abbr.
inline code
Ctrl + C
Highlighted
Primary and accent text
Integer bibendum malesuada libero vel eleifend. Fusce iaculis turpis ipsum, at efficitur sem scelerisque vel. Aliquam auctor diam ut purus cursus fringilla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Cras fermentum velit vitae auctor aliquet. Nunc non congue urna, at blandit nibh. Donec ac fermentum felis. Vivamus tincidunt arcu ut lacus hendrerit, eget mattis dui finibus.
Donec nec egestas nulla. Sed varius placerat felis eu suscipit. Mauris maximus ante in consequat luctus. Morbi euismod sagittis efficitur. Aenean non eros orci. Vivamus ut diam sem.
Ut sed quam non mauris placerat consequat vitae id risus. Vestibulum tincidunt nulla ut tortor posuere, vitae malesuada tortor molestie. Sed nec interdum dolor. Vestibulum id auctor nisi, a efficitur sem. Aliquam sollicitudin efficitur turpis, sollicitudin hendrerit ligula semper id. Nunc risus felis, egestas eu tristique eget, convallis in velit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque urna diam, tincidunt nec porta sed, auctor id velit. Etiam venenatis nisl ut orci consequat, vitae tempus quam commodo. Nulla non mauris ipsum. Aliquam eu posuere orci. Nulla convallis lectus rutrum quam hendrerit, in facilisis elit sollicitudin. Mauris pulvinar pulvinar mi, dictum tristique elit auctor quis. Maecenas ac ipsum ultrices, porta turpis sit amet, congue turpis.
badge works on any inline element. kbd is a
keycap, not a badge.
Bring the brief, the details, and the next step together. A simple card gives related content a clear home without competing for attention.
drawer anchors to the bottom;
drawer="top|left|right" anchors to any other edge.
Submit defaults to primary and reset to outline, from the element's own semantics. A reset button no longer looks like a delete button.
A label is a row: its text sits beside the control, and a text
control takes the rest of the line. stack turns it into
a field instead, with the label above a full-width control.
Edit client details
row and col pick the axis,
gap-xs / gap-s / gap-m / gap-l size the
space between children, and justify and
items place them along the axis and across it. Headings
and paragraphs drop their block margins inside a row,
since the container is already spacing its children with
gap. grid fit makes the form two columns
when there is room and one on a phone. grow gives the
title the space left beside the account button; nowrap
keeps that header on one line. Use full-width when a
button should fill its container.
Your changes are being synced.
The client was saved successfully.
Your trial ends in 3 days. Add a payment method to keep your projects.
The connection was interrupted. Please try again.
notice styles the message; notice="success", "warning" and "error" add a coloured edge. Choose role="status" for updates or role="alert" for urgent errors when adding messages dynamically.
Set density="compact" or density="comfortable" on a container to size its controls together. A label tag wraps a real, keyboard-accessible file input; visually-hidden keeps it available to assistive technology.
loading draws the spinner;
aria-busy="true" carries the meaning. Use both.
aria-busy is a true/false state, so it cannot be a
styling hook on its own. On a button, link or
summary the spinner replaces the icon rather than
sitting next to it. With reduced motion enabled, the spinner keeps
turning gently while decorative animations stop. Add
disabled to a busy button to prevent keyboard activation.
Set the dimensions for the layer.
Signed in as ada@example.com
A popover opens centred above its anchor.
placement moves it: top or
bottom, on their own or with -start /
-end to line its edge up with the anchor's. Anchored
placement is progressive enhancement — engines without CSS
anchor positioning centre the popover in the viewport instead, and
where it is supported a popover near an edge flips to the other side
rather than opening off-screen. The layout attributes work inside one:
this menu is a col gap.
Use placement="center" for a viewport-centred popover.
Focus either region to scroll with the keyboard, or use a trackpad or touch gesture.
Radix Primitives An open-source UI component library.
| Person | Most interest in | Age |
|---|---|---|
| Chris | HTML tables | 22 |
| Dennis | Web accessibility | 45 |
| Sarah | JavaScript frameworks | 29 |
| Karen | Web performance | 36 |
| Average age | 33 | |
| Person | Most interest in | Age |
|---|---|---|
| Chris | HTML tables | 22 |
| Dennis | Web accessibility | 45 |
responsive gives a too-wide table its own horizontal
scrollbar so it can never stretch the page; pair it with
white-space: nowrap if you want the columns to keep
their natural width instead of cramming. Prefer it on a wrapper
— <div responsive> — because on the
table itself it has to switch the table to a block box, which makes
the columns shrink to their content.
responsive="stack" instead breaks each row into its own
card under 600px, printing every cell's data-label
beside its value — narrow the window to see it. Both drop the
table role where they change display; put
role="table", role="row" and
role="cell" back if screen-reader users need the grid.
| Person | Most interest in | |
|---|---|---|
| Chris | HTML tables | |
| Dennis | Web accessibility |
reveal on the row keeps its controls out of the way
until you point at it — hover a row, or tab into one, and they
appear. Where the pointer cannot hover they are never hidden.
tooltip names an icon-only button on hover and focus,
but it is drawn in CSS and assistive tech never sees it, so the
aria-label beside it is doing the real work.
tag gives any element the button's exact appearance and
every button variant — they share the same rules, so they
cannot drift apart. Only a tag that is an a,
button, summary or label gets the hand cursor and
the hover, active and focus states; a plain
<span tag> never pretends to be clickable.
The wrapping label toggle makes the icon clickable and
keyboard-operable natively — no JavaScript.
field groups a label, control and descriptions. In a validation form, native :user-invalid reveals the error after interaction; aria-invalid="true" supports errors supplied by your application. Keep descriptions connected with aria-describedby.
fieldset segmented styles real radio buttons. Tab into the group and use the arrow keys to change selection.
label choice highlights its native checked or focused input. Radio cards select one option; checkbox cards allow independent choices.
ul list or ol list aligns row content and actions. A single anchor can make a whole row a link. Keep role="list" when removing native list markers.
Plain dl, dt and dd create a responsive label/value layout. Optional div wrappers can group each pair. On phones the values sit below their labels.
Page 1 of 3 · Ada Lovelace
nav pagination styles page links and aria-current="page". Your application supplies page URLs and current state; this preview changes the sample record locally. An unavailable page is a span or a disabled button, rather than a clickable disabled-looking link.
avatar works on an image or an element containing initials. Use small, large or --avatar-size to change its size. avatars overlaps a group. Supply image alt text or an accessible name for initials.
empty groups an illustration, heading, explanation and action. Your application decides when to show it.
ol steps presents progress supplied in the markup. Mark finished steps with complete and the current one with aria-current="step". It stacks vertically on phones.
Ada opened the autumn planning workspace.
Grace and Katherine joined the project.
The project brief is ready for review.
Use a native meter for a measurement within a known range, such as a quota. Use progress for work being completed. Native low, high and optimum define the value ranges.
fieldset rating keeps native radio semantics, arrow-key navigation and form values. The stars up to the selected value are filled using CSS.
indicator positions a badge or status dot on a control or avatar. Include the count or status in accessible text, not just the dot's colour.
A shared workspace for the autumn launch.
The team has completed the project brief.
Team plan · Monthly billing · Email notifications enabled.
nav tabs styles ordinary navigation links and aria-current. These links jump to sections; they retain link semantics. Content-switching ARIA tabs require additional focus and keyboard handling.
Bring your team's goals, audience and direction together in a thoughtful project brief.
Turn your first sketches into a useful prototype, ready for feedback from the whole team.
Make the final checks, celebrate the progress and welcome your first customers.
carousel provides native scrolling and CSS scroll snapping. Swipe, focus the carousel and use arrow keys, or follow the slide links. Set --slide-size to change the slide width. There is no autoplay.