Skip to content

Data & Display

Tables, boards, timelines and long-form content - everything that shows real data.

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 revenue 48.2k EUR
Churn 2.1%
Open tickets 17

In a row

Visitors 12,480
Bookings 312
Avg. basket 64EUR

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

Storage 3.1 of 10 GB
3.1 of 10 GB
API calls 8,200 of 10,000
8,200 of 10,000
Seats 24 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

invoice-0917.pdf

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

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.

Mon 14.09.

Lentils with spaetzle

Two sausages, a splash of vinegar, and bread on the side.

10.90 Euro

Tue 15.09.

Roast pork

Bread dumpling, red cabbage and a dark gravy.

11.90 Euro

Wed 16.09.

Cheese spaetzle

Hand-scraped, mountain cheese, roasted onions, leaf salad.

veggie

10.50 Euro

Thu 17.09.

Schnitzel in cream sauce

Pork, with spaetzle and a small salad.

12.90 Euro

Today, Fri 18.09.

Baked fish fillet

In beer batter, with warm potato salad and remoulade.

11.90 Euro

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.

Mon 14.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.

Tue 15.09.

Roast pork 11.90 €

Bread dumpling, red cabbage, dark gravy.

Cheese spaetzle veggie 10.50 €

Mountain cheese, roasted onions, leaf salad.

Wed 16.09.

Barley stew veggie 9.50 €

Root vegetables, simmered since morning.

Beef roulade 13.50 €

Mashed potato and green beans.

Thu 17.09.

Schnitzel in cream sauce 12.90 €

Pork, with spaetzle and a small salad.

Mushroom ragout veggie 10.90 €

With a bread dumpling.

Today, Fri 18.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.

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"
11/2021 Certified Kubernetes Administrator (CKA) | CNCF
06/2020 - 07/2021
(1 year 1 month)

Mid-Level Developer

DevSolutions LLC • Remote

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.

  1. Mira Brandt approved invoice 2026-041
  2. Jonas Reuter moved "Booking app" to review
  3. Payment for invoice 2026-038 failed - card declined
  4. Tom Aldridge invited Mara Kessler to the workspace

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.

Mountain range at sunrise
First light on the ridge. mw-mosaic-big makes a photo the centrepiece.
Snowy mountain peak under a starry sky
Summit night, 3,000 metres up.
Hot air balloon in a morning sky
Palm tree against a sunset over the sea
The last evening on the island.
Peaceful lake
Television tower above the city at night
Waterfall between mossy cliffs
Two hours up the gorge, and worth every step of it.
City skyline at night
Lighthouse on a cliff at dusk
Northern lights over a snowy forest
Minus eighteen degrees. Nobody minded.
Desert dunes
Snowy hills

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.

Lighthouse on a cliff at dusk

Last light over the north cape. Stood there until the lamp came on.

Hot air balloon in a morning sky

Up before sunrise for this one.

Ocean waves rolling to the horizon
Snowy mountain peak under a starry sky

3,000 metres, one thermos of tea and far too many stars to count.

#alps #nightsky

Palm tree against a sunset over the sea
City skyline at night
Path through a sunlit forest

Found the quiet trail. Nobody else for two hours.

Television tower above the city at night
Waterfall between mossy cliffs

Two hours up the gorge. #waterfall #hiking

Peaceful lake
Northern lights over a snowy forest

Minus eighteen degrees. Nobody minded.

Desert dunes
Tent glowing under the milky way

Camp at 2,400 metres.

Mountain range at sunrise
Snowy hills

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
Beach at sunset with waves running up the sand Lighthouse on a cliff at dusk
Nights
Tent glowing under the milky way Television tower above the city at night
North
Northern lights over a snowy forest Snowy mountain peak under a starry sky
Hikes
Path through a sunlit forest Waterfall between mossy cliffs
Up high
Hot air balloon in a morning sky

Content Slider

Image Slider

Mountain Landscape
Lake
Forest
Field
Trees

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.

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