Tables, boards, timelines and long-form content - everything that
shows real data.
Page Header
The start of a content page: title and subtitle on the left, actions on the
right, wrapping when it gets tight. The counterpart to
mw-section-head, which opens a section of a landing page rather
than a page of an application.
With Actions
Blog Posts
14 entries · 3 drafts
Page content follows here.
Combined with Meta Info
The counters fit naturally underneath the title instead of a subtitle
line.
Blog Posts
Amount: 14
Drafts: 3
Published: 11
Compact, with Filters
mw-page-header-filters puts fields in one row with the
actions and moves them under the title below lg.
mw-page-header-compact is the size for an app screen, and
mw-page-header-sticky keeps it under the fixed header while a
list scrolls.
Invoices
128 entries
Without a Separator
mw-page-header-plain drops the bottom rule for pages that
bring their own.
Settings
Manage your account
Meta Info
The line of small facts that sits with a heading - author, date, reading time,
status. One wrapping row, with the separators drawn by CSS rather than typed
into the markup.
Amount: 5
Started: 1
Deactivated: 1
Tables
Rows for data that has columns. On a phone a wide table either scrolls inside
its own frame or turns each row into a card -
mw-table-responsive for the first,
mw-table-cards for the second. The compact variant is for the
tables that hold a screenful at a time.
Basic Table
This is the basic table that supports all functions except the complete
responsive feeling with the cards - five columns do not fit a phone, so it
sits in a mw-table-responsive wrapper.
mw-table-compact is the same table with less spacing and
smaller type.
#
Name
Position
Location
Budget
1
Mara Kessler
Developer
New York
1,204.50
2
Tom Aldridge
Designer
London
87.00
3
Jonas Reuter
Manager
Berlin
15,930.25
The Budget column uses
mw-text-currency - right-aligned with tabular, lining
digits and no wrapping mid-number. The alignment comes from the right
edge, so it works the same for 1,204.50 and
1.204,50; only the number of decimal places has to be
consistent per column. If you only want the fixed-width digits without the
alignment, use mw-text-numeric. For the input side there
is mw-input-numeric.
Subtle Header & Sticky Header
mw-table-subtle keeps the header quiet - a full primary bar
across every column shouts louder than the data it labels.
mw-table-sticky-head keeps it visible while the body scrolls;
it needs a scroll container with a height limit, which
mw-table-responsive-scroll provides. Scroll inside the table
to see it. Its height comes from
--mw-table-scroll-height (400px, 260px below sm)
- override it per table with
style="--mw-table-scroll-height: 250px".
#
Name
Position
Budget
1
Mara Kessler
Developer
12,400
2
Tom Aldridge
Designer
9,800
3
Jonas Reuter
Manager
21,050
4
Alice Brown
Developer
11,300
5
Charlie Davis
Analyst
7,600
6
Emma Wilson
Designer
10,150
7
Frank Miller
Developer
13,900
8
Grace Lee
Manager
19,700
9
Henry Clark
Analyst
8,250
10
Ivy Turner
Developer
14,600
11
Jack Morris
Designer
9,400
12
Karen Hall
Manager
22,800
13
Liam Scott
Developer
12,950
14
Mia Adams
Analyst
7,900
Scroll Hint
mw-table-responsive-hint fades the right edge, so it is
visible that more columns are hiding behind it. The wrapper below is
capped at 520px to force the overflow; normally the viewport does that.
Invoice
Customer
Issued
Due
Status
Net
VAT
Total
2026-0042
Fischer GmbH
19.08.2026
19.09.2026
Open
1,012.18
192.32
1,204.50
2026-0041
Wagner AG
12.08.2026
12.09.2026
Paid
73.11
13.89
87.00
2026-0040
Schmidt & Partner
02.08.2026
02.09.2026
XRechnung
13,386.76
2,543.49
15,930.25
Opt-in, unlike the automatic hint on a tab bar, and by a different
mechanism: a table paints its own opaque surface, so the gradient trick
used there would sit behind the rows and never show. A mask sits in front
and does show - but a mask has no local attachment, so it
cannot fade away once the last column is reached. Put the class on the
tables you know overflow, leave it off the ones that fit.
Responsive Table
This is the same table but with cards for smaller screens
#
Name
Position
Location
1
Mara Kessler
Developer
New York
2
Tom Aldridge
Designer
London
3
Jonas Reuter
Manager
Berlin
Sortable, Selectable, Sticky
aria-sort on a header draws which way the column runs - the
button inside does the sorting. A checked box in the first cell selects the
row, and mw-table-bulk around the table shows its bar while any
row is checked, with the count filled in by CSS where the bar is left empty.
mw-table-sticky-col keeps the first column in place while a wide
table scrolls sideways.
Select
Owner
Harbourline
Relaunch
12.400 EUR
Mira Brandt
2026-10-14
Pfotenwerk
Booking app
8.950 EUR
Jonas Reuter
2026-11-02
Kontor Nord
Audit log
3.200 EUR
Tom Aldridge
2026-10-21
Bäckerei Lind
Homepage
2.480 EUR
Mara Kessler
2026-12-01
selected
Client
Project
Budget
Owner
Due
Quarter
Contract
Office
Harbourline
Relaunch
12.400 EUR
Mira Brandt
2026-10-14
Q4
Retainer
Berlin
Pfotenwerk
Booking app
8.950 EUR
Jonas Reuter
2026-11-02
Q4
Retainer
Berlin
Kontor Nord
Audit log
3.200 EUR
Tom Aldridge
2026-10-21
Q4
Retainer
Berlin
Bäckerei Lind
Homepage
2.480 EUR
Mara Kessler
2026-12-01
Q4
Retainer
Berlin
Stats & Meters
The numbers a dashboard opens with, and how full something is. A stat sizes
its value to the room it gets, not to the window - the same markup in a
sidebar and in a wide row. The meter is the native <meter>,
so its thresholds are attributes and its tone follows from them.
Monthly revenue48.2k EUR
Churn2.1%
Open tickets17
In a row
Visitors12,480
Bookings312
Avg. basket64EUR
mw-stat-group lines the stats up with a rule between them
once it is 30rem wide and stacks them below that. The arrow carries the
direction and the sign belongs in the text, so neither depends on colour.
mw-stat-delta-invert swaps the tones for a number where up is
the bad direction.
Meters
Storage3.1 of 10 GB
3.1 of 10 GB
API calls8,200 of 10,000
8,200 of 10,000
Seats24 of 25
24 of 25
Green, amber and red are the browser's own reading of
low, high and optimum: with the
optimum at 0, less is better, and the tone flips as usage climbs past
each threshold. mw-meter-sm and mw-meter-lg
match the progress bar sizes.
Chat
The pieces of an assistant or support chat. The bubble takes the framework's
silhouette - sharp on the corner the message comes from, mirrored for the
person typing. Streaming, scrolling and sending stay the application's job;
this is only what it renders into.
Conversation
Today
You
Which invoices from September are still open? The export at
https://app.example.com/billing/exports/2026-09/invoices-open.csv
looks incomplete.
Searched 42
invoices
AI
Assistant
Three are open. The export skips drafts, which is why it looked
short:
INV-2026-0912 1.240,00 EUR due 2026-10-05
INV-2026-0917 380,50 EUR due 2026-10-12
INV-2026-0923 2.115,00 EUR due 2026-10-20
AI
Assistant is typing
Composer
Suggestions
Prompt
The field grows with what is typed and scrolls from twelve lines on.
Where field-sizing is missing it keeps a three-line box.
Like every field it stays light in both themes.
While it works
Thinking about your invoices...
mw-chat-thinking sweeps a highlight across the text,
mw-chat-typing bounces three dots. Both stand still under
reduced motion, and the log itself carries role="log" so
a screen reader announces new messages.
Kanban
A board is a mw-kanban with one mw-kanban-column per
status, a ticket a plain mw-card with
mw-kanban-card on top. The priority is the regular
mw-card-ribbon and brings its colour along on its own.
mw-kanban-compact tightens the padding and clamps the description
to two lines instead of four - for boards with many lanes or a sidebar next to
them.
Backlog
0
Low
Dark mode for the export dialog
The dialog still renders on a hard white sheet while the rest of the
app follows the theme. The print stylesheet forces a light background
on purpose, and that rule leaks into the preview pane because both
share the same wrapper class. Splitting the two is probably enough,
but the header and the footer of the dialog need checking as well.
Evaluate container queries
Spike only - check whether the grid could drop a few breakpoints.
No tickets
In Progress
0
High
Sticky table header jitters
On Safari the header shifts by a pixel while scrolling. Looks like a
subpixel rounding issue on the border, since it only shows up at zoom
levels that are not a multiple of 25 percent. Chrome and Firefox are
both clean, so a transform-based fix would likely cost more than it
buys us here.
Medium
Range input on touch devices
The thumb is too small to grab reliably; the track needs a bigger hit
area.
No tickets
Review
0
Medium
Stepper: vertical variant
Draws its own connector line, so the markup stays lighter than the
horizontal one.
No tickets
Done
0
Tooltips no longer clipped
Cards stopped creating a stacking context, so tooltips can escape
their bounds again.
No tickets
Title
Text
Calendar
Month, compact and week share every class - a week is seven cells instead of
forty-two, mw-calendar-compact drops the dots and a third of the
height. The status dots come in as
data-calendar-markers='{"2026-08-19": ["success", "warning"]}'.
What a dot means belongs to the caller: the same calendar reads
“request pending / booked / time offered” in a scheduling app and
something else entirely on a public booking page. So the colour is a property,
--mw-calendar-dot, settable per dot or inherited from the cell -
mw-calendar-dot-success and friends are named presets for it, not
the only way in.
Any colour, set on the dot itself--mw-calendar-dot
Month
Slots free
Almost booked
Fully booked
Public holiday
Week
Slots free
Almost booked
Fully booked
Public holiday
Lunch menu
Nothing below is a lunch-menu component. It is mw-card,
mw-price, mw-date-stamp and two grid classes - a
weekly menu is a composition, not a widget. One day per row: five columns
would squeeze a dish name into a fifth of the page, and a wrapping grid would
orphan the fifth card into a row of its own. mw-grid-even gives
every row the height of the tallest, so a day with a second line of
description does not make its card taller than the rest of the week.
mw-date-stamp answers to the card, not the viewport. On a narrow
card it is a muted line above the title; once the card is wide enough that a
single column would leave its right half empty - as every card in a stacked
list is - the same markup becomes the column on the left. Because the width it
switches at is the card's, a stamp behaves the same whichever grid it is
dropped into. mw-date-stamp-today fills that column instead of
recolouring it: the price is already primary, and two blues compete where one
would point.
Mon14.09.
Lentils with spaetzle
Two sausages, a splash of vinegar, and bread on the side.
In beer batter, with warm potato salad and remoulade.
11.90Euro
Two dishes a day
The day is the card, so a second dish is another row inside it rather than a
second card. With a price per dish there is nothing left for a price column to
hold, so it goes instead where a printed menu puts it - on a
mw-leader-row, at the end of the line it prices. The stamp does
not change at all: it still centres against whatever the card holds beside it,
two rows or ten.
Mon14.09.
Lentils with spaetzle
10.90 €
Two sausages and a splash of vinegar.
Potato soup with marjoram
veggie
6.50 €
With a slice of farmhouse bread.
Tue15.09.
Roast pork
11.90 €
Bread dumpling, red cabbage, dark gravy.
Cheese spaetzle
veggie
10.50 €
Mountain cheese, roasted onions, leaf salad.
Wed16.09.
Barley stew
veggie
9.50 €
Root vegetables, simmered since morning.
Beef roulade
13.50 €
Mashed potato and green beans.
Thu17.09.
Schnitzel in cream sauce
12.90 €
Pork, with spaetzle and a small salad.
Mushroom ragout
veggie
10.90 €
With a bread dumpling.
Today,Fri18.09.
Baked fish fillet
11.90 €
Beer batter, warm potato salad, remoulade.
Pancake soup
5.80 €
Beef broth with chives.
The menu changes every week. No reservation, while the pot lasts.
Contact
The practical block at the end of a site - when we are open, how to reach us.
Only the second half is a component: mw-contact is an
<address> with its italics undone and a label column that
keeps the values under each other. The hours are a <dl> of
mw-leader-row, because a day and its times with a line between
them is the row that component already is.
Opening hours
Monday to Friday
11.30 - 14.00
17.00 - 23.00
Saturday
17.00 - 23.00
Sunday
11.30 - 20.00
Hot food all day on Sunday. Otherwise the kitchen closes an hour before
the house does.
The same frame as a calendar - an arrow on each side of the title, content
below - but the body is yours. Not a page-number list; the paging itself is
your job, mw-pagination-loading dims the body while the next page
is on its way.
Week 10
Week 10 Content
Put anything in here - text, a form, a table, a chart. The frame only
gives it a title and two arrows.
Numbered Pages
mw-pagination-pages for a list or a table.
aria-current="page" marks where you are,
aria-disabled="true" an arrow that leads nowhere. On a phone the
numbers give way to mw-pagination-status between the arrows.
Timelines
Big Timeline
You can use every card within the timeline content wrapper.
01/2023 - Present
Lead Developer
Innovatech Inc • San Francisco
Overseeing cross-functional development teams, defining technical
strategy, and aligning product roadmaps with business goals. Driving
innovation and delivering high-impact features.
05/2023
AWS Certified Solutions Architect - Professional
08/2021 - 12/2022
(1 year 4 months)
Senior Developer
Innovatech Inc • San Francisco
Led technical design, mentored junior developers, and spearheaded
code reviews. Improved CI/CD pipelines and introduced best practices
for scalable frontend architecture.
02/2022
Speaker at JSWorld Conference: "Scaling Vue.js"
Took ownership of feature development, optimized application
performance, and integrated RESTful APIs. Collaborated closely with
designers and backend engineers.
10/2020
MongoDB Certified Developer Associate
02/2018 - 05/2020
(2 year 3 months)
Junior Developer
StartupXYZ • Berlin
Contributed to UI components, fixed bugs, and wrote unit tests in a
collaborative Agile team. Gained hands-on experience with HTML, CSS,
and JavaScript.
Simple Timeline
Here you can also use every card within the timeline content wrapper.
2023-11-10
Website Launch
Deployed the initial version of our public website with responsive
design, SEO optimizations, and analytics integration.
2024-03-22
v1.1 Release
Rolled out version 1.1 featuring performance improvements, a dark mode
toggle, and enhanced accessibility support.
2024-06-15
DevCon 2024
Spoke at DevCon 2024 about “Scalable CSS Architecture” and
demonstrated our timeline component to 500+ attendees.
2024-10-05
Hackathon Champion
Led a cross-functional team to victory in the annual internal
hackathon with a productivity plugin prototype.
Hackathon Champion
Led a cross-functional team to victory in the annual internal
hackathon with a productivity plugin prototype.
Compact Timeline
An activity feed or an audit log: a dot and a time per line, as many lines as
there are, no entrance to wait for. The dot takes a tone from
mw-timeline-compact-success and its siblings.
Mira Brandt approved invoice 2026-041
Jonas Reuter moved "Booking app" to review
Payment for invoice 2026-038 failed - card declined
Tom Aldridge invited Mara Kessler to the workspace
Image Gallery
A slider for photos: swipe, arrows, dots and a caption read off the slide
itself. The dots are real buttons, so the fourth picture is reachable without
a mouse.
Beautiful Mountain
Portrait Gallery
Upright photos in a strip the browser scrolls itself: a swipe on a phone,
arrows under a mouse, and the next photo always peeks in at the edge. One
slide on a phone, two and a half on a tablet, three on a desktop. A photo in
the other orientation - the lake below - is not cropped to a sliver but shown
whole, over a blurred copy of itself.
mw-portrait-gallery-gap-sm and
mw-portrait-gallery-gap-lg change the gaps.
North Cape
The lamp comes on just after the sun goes.
Summit night
3,000 metres and one thermos of tea.
Landscape, not cropped
Shown whole over a blurred copy of itself.
Blue hour
The tower, the moon and not a single cloud.
Story shape
mw-portrait-gallery-tall turns the slides into 9:16, the shape of
a phone screen - for stories, reels and screenshots. A video works like a
photo; the square balloon gets the same blurred frame the lake did.
Sunrise
A muted, looping video.
Mosaic
Photos of any shape in one grid. The script reads each photo's proportions
from its width and height and gives it a tile to
match - wide for landscape, tall for portrait, square for the rest - and the
smaller tiles fill the holes. The tile crops, the lightbox does not: a tap
opens the photo whole with its caption, and a swipe moves on to the next one.
mw-mosaic-gap-sm and mw-mosaic-gap-lg change the
gaps.
First light on the ridge. mw-mosaic-big makes a photo the
centrepiece.
Summit night, 3,000 metres up.The last evening on the island.Two hours up the gorge, and worth every step of it.Minus eighteen degrees. Nobody minded.
Photo Feed
Photos in the grid everyone knows from their phone, in a framed box that shows
three rows and scrolls - mw-feed-rows-2 shows two,
mw-feed-plain drops the frame. A strip of the next row stays in
view, so the box reads as scrollable. A tap opens the photo as a card, with
its text if the figcaption has any. No script: the tile is a
button with popovertarget, the card a popover - in
Angular that is [attr.popovertarget] and a matching
[id]. mw-feed-square switches to square tiles.
Last light over the north cape. Stood there until the lamp came on.
Up before sunrise for this one.
3,000 metres, one thermos of tea and far too many stars to count.
#alps #nightsky
Found the quiet trail. Nobody else for two hours.
Two hours up the gorge. #waterfall #hiking
Minus eighteen degrees. Nobody minded.
Camp at 2,400 metres.
Story Archive
Stories that stay. A circle opens its story full screen on a phone and
phone-shaped on a desktop; every frame shows for five seconds and a bar at the
top counts them off - that part is CSS alone. A few lines of script add the
rest: a tap on the right moves on, on the left goes back (arrows under a
mouse), a video starts when its frame comes up, the story closes at its end.
Holding a finger on it or the pause button stops it; Escape, the cross or a
click beside it close it. With reduced motion set in the system nothing plays
by itself - the frames become a strip to swipe through instead.
Coast
Nights
North
Hikes
Up high
Content Slider
Image Slider
Testimonials
A quote card with its source - a figure, because quote and
attribution belong together. One voice may stand above the grid as
mw-testimonial-featured; the rest flow in
mw-columns-3, the masonry layout for cards of unequal height. The
cards below also carry mw-reveal - scroll them into view to see
the entrance. Three of them are dated: mw-testimonial-date is a
time element on the right edge of the source line, month and
year. It is optional on purpose - a dated quote ages, so only show it where
the voices are kept fresh.
We rebuilt our whole customer portal on this in three weeks. The team never
argued about spacing or shadows again - the framework had already decided,
and it had decided well.
Maren K.
· Head of Engineering
The dark theme just worked. We flipped one class and every component
followed.
Jonas R.
· Frontend Developer
I came for the grid and stayed for the corner accents. Our app finally
looks like one product instead of five teams.
Priya S.
· Product Designer
Small CSS, no build step, readable class names.
Tom W. · Freelancer
The form controls line up with the buttons out of the box. That alone
saved us a week of pixel pushing across three breakpoints - and the touch
targets grow on their own on mobile.
Aylin D. · Agency Lead
Swapped one primary color, the whole palette followed.
Ben L. · Indie Hacker
Our legal pages, our landing page and our admin tables all speak the same
language now.
Carla M. · CTO
Prose
Long-form running text - a legal page, terms, a plain article. One class on
the container, bare h2/h3/p/ul
inside: exactly what a CMS or a JSON-driven page produces. Headings stay
deliberately small - in a document they structure the reading, they do not
compete with the page title.
1. Scope
These terms apply to every order placed through this site. Deviating
conditions of the customer do not apply unless expressly confirmed in
writing.
2. Contract
The presentation of products is not a binding offer. A contract comes into
existence when the order confirmation arrives, at the latest with the
delivery of the goods.
2.1 Cancellation
Consumers may cancel within fourteen days without giving a reason. The
period starts on the day the goods arrive. For the cancellation to count,
one of the following is enough:
an informal e-mail naming the order number
the returned goods with a short note
the cancellation form from the appendix
3. Prices
All prices are final prices and include the statutory value-added tax.
Shipping costs are shown separately before the order is placed.
Media
Self-hosted audio and video. The framework ships no player - the native
controls are the player, and accent-color already brands them.
The wrapper makes the element a full-width block; a video also
gets the surface silhouette and a resting shadow, same markup with a
<video> element inside.
Audio with caption
A short chime, served from this site.
Bare, without a card
Palette
Two colors. Everything else - bar, ink, borders, tints - is derived from
them at runtime.
Variants
Every switch is one class on <html> or one custom property - no build,
no rebuild. The box at the bottom is what a project would carry, and it
reads back: paste someone else's setup in to see it. The link does the same
- Copy link hands someone this page exactly as it stands.
Shown in the preview
Surfaces, controls and type - the section at the bottom of this page.