App data
Tables, charts and content widgets for real apps: all generated from data attributes, all themed with tokens.
Table
sf-table in sf-table-wrap. Add data-sf-tablesort and data-sf-selectable; sf-table--stack turns rows into cards on phones. Set --sf-table-h on the wrap for a scrolling body with a sticky header.
| Order | Customer | Status | Total | Date |
|---|---|---|---|---|
| #1042 | Maya Okafor | Paid | $1,240.00 | Oct 12, 2026 |
| #1043 | Daniel Weiss | Pending | $318.50 | Oct 13, 2026 |
| #1044 | Sofia Ricci | Paid | $89.00 | Oct 13, 2026 |
| #1045 | Arjun Patel | Refunded | $742.25 | Oct 14, 2026 |
| #1046 | Lena Fischer | Paid | $2,015.00 | Oct 15, 2026 |
| #1047 | Tomas Novak | Pending | $56.40 | Oct 16, 2026 |
| #1048 | Grace Liu | Paid | $460.00 | Oct 16, 2026 |
| #1049 | Omar Haddad | Paid | $129.99 | Oct 17, 2026 |
Data grid toolbar
sf-gridbar with data-sf-gridbar and data-sf-for="tableId": live search, filter chips, density toggle and a column menu.
| Name | Role | Status | Location | Projects |
|---|---|---|---|---|
| Maya Okafor | Design lead | Active | Lagos | 12 |
| Daniel Weiss | Engineer | Away | Berlin | 8 |
| Sofia Ricci | Product manager | Active | Milan | 15 |
| Arjun Patel | Engineer | Offline | Pune | 6 |
| Lena Fischer | Researcher | Active | Zurich | 9 |
| Tomas Novak | Designer | Away | Prague | 11 |
| Grace Liu | Engineer | Active | Toronto | 14 |
| Omar Haddad | Support | Offline | Amman | 4 |
List and list item
sf-list with sf-list__item (lead, main, trail). The swipe variant adds sf-swipe + data-sf-swipe: drag a row left to reveal actions.
- Maya Okafor9:41
- Daniel WeissYesterday
- Sofia Ricci
- Arjun PatelNew
-
Lena Fischer2m
-
Tomas Novak1h
-
Grace Liu3h
Stat / KPI card
sf-stat with a label, value (add data-sf-statcount to animate it), delta (--up, --down, --flat) and a sparkline.
Sparkline
Inline SVG drawn from data-sf-sparkline and data-sf-values. Options: data-sf-width, data-sf-height, data-sf-area, data-sf-smooth="false", sf-spark--fluid.
Bar chart
data-sf-chart="bar" or "hbar". Data from data-sf-values + data-sf-labels, data-sf-data JSON, or a script type=application/json child. Hover, or focus the chart and use arrow keys.
Line / area chart
data-sf-chart="line" or "area": draw-in animation, crosshair and tooltip on hover or arrow keys, multiple series with a legend.
Donut / pie chart
data-sf-chart="donut" or "pie". Hover a segment or legend row: it pops, the centre label updates.
Progress group, stacked bar, goal meter
sf-meters / sf-dmeter use --sf-value. sf-stack takes flex weights in --v. sf-goal is generated from data-sf-goal with role="meter".
- Design 40%
- Build 25%
- Review 20%
- Admin 15%
Heatmap
Calendar contribution grid from data-sf-heatmap with data-sf-values (oldest to newest) or a date-keyed data-sf-data object. Choose a colour with data-tone.
Calendar
sf-cal from data-sf-calendar: today ring, selected day, event dots, month-switch animation, full keyboard grid (arrows, Home/End, PageUp/PageDown). Add data-sf-agenda for the day list.
Date picker and range picker
sf-datepicker with data-sf-datepicker (add data-sf-range for a range). Type an ISO date, or open the popover. Esc closes.
Kanban board
data-sf-kanban: drag cards between columns (mouse anywhere, touch by the grip). Keyboard: focus a card, Space to pick up, arrows to move, Space to drop, Esc to cancel.
To do
0Audit colour contrast
Plan the Q4 roadmap review
In progress
0Ship the billing importer
Redesign empty states
Done
0Set up analytics events
Timeline / activity feed
sf-timeline with sf-timeline__group per day, an icon dot per event (tinted with data-tone).
Today
Daniel Weiss merged billing-importer into main
Maya Okafor commented on Empty states
"Let's try a friendlier illustration for the inbox."
Yesterday
Lena Fischer uploaded research-notes.pdf
Arjun Patel joined the workspace
Sofia Ricci published release v2.4
Avatar group
sf-avgroup stacks sf-avatar. data-sf-max="N" collapses the rest into a +N chip. Hover or focus to spread.
Chat
sf-chat with sf-msg bubbles, sf-typing and sf-composer. Enter sends, Shift+Enter adds a line. data-sf-autoreply simulates a reply.
Comment thread
sf-thread of nested sf-comment. sf-reactions toggles with a count; Reply opens an inline composer.
Yes, the shapes are CSS only, so it costs nothing to reuse them.
Adding it to the sprint board.
Nice work everyone. Reduced motion is respected too, which I appreciate.
Chip / tag
sf-chip: static, selectable (button with aria-pressed inside data-sf-chips), removable (sf-chip--removable) and a tag input (sf-chips + sf-chips__input). Colours via data-tone.
Notification list
sf-notifs grouped by day, unread dot, tap to mark read, or swipe a row right (data-sf-swipe="commit"). Mark all read is data-sf-notif-all.
Today
-
Mark read
-
Mark read
-
Mark read
Earlier
-
Mark read
-
Mark read
Profile card and user hover card
sf-profile is a full card. sf-hovercard wraps a trigger link and a card that opens on hover or keyboard focus (Esc dismisses).
Maya Okafor
Design lead building calm, springy interfaces. Coffee, type and tiny animations.
File list and file tile
sf-file with data-type (pdf, doc, xls, img, zip, code, video, audio) and data-status (uploading, done, error). The icon is pure CSS. Try Retry.
- Q4-roadmap.pdfUploaded
- revenue-forecast.xlsx62%
- hero-illustration.pngFailed
- brand-assets.zipUploaded
Code block
sf-code with data-sf-code="js|css|py|sh|html|json": light tokenizer, line numbers, tab label, copy button (data-sf-copy), data-sf-highlight="2,5-6".
// Import invoices in batches
async function importInvoices(rows, size = 50) {
const results = [];
for (let i = 0; i < rows.length; i += size) {
const batch = rows.slice(i, i + size);
const res = await fetch("/api/invoices", {
method: "POST",
body: JSON.stringify(batch),
});
results.push(await res.json());
}
/* done */
return results.flat();
}
/* springy press */
.btn {
--spring: cubic-bezier(.3,1.7,.5,1);
min-height: 48px;
border-radius: 999px;
transition: scale .2s var(--spring);
}
.btn:active { scale: 1.12 .84; }
# install and run
npm install soft-ui
npm run dev -- --port 3000
echo "ready on http://localhost:3000"
Description list / spec table
sf-dl with sf-dl__row (dt + dd). Modifiers: --stack, --spec (framed), --tiles.
- Display
- 6.1-inch OLED, 120 Hz
- Battery
- 3,300 mAh, up to 24 hours
- Storage
- 128 GB / 256 GB / 512 GB
- Weight
- 171 g
- Connectivity
- 5G, Wi-Fi 6E, Bluetooth 5.3
- Customer
- Maya Okafor
- maya@example.com
- Plan
- Team, billed yearly
- Renews
- March 3, 2027
- Open issues
- 23
- Merged PRs
- 148
- Contributors
- 12
- Latest release
- v2.4.1
Image gallery and lightbox
sf-gallery with data-sf-lightbox: click an item for a spring-zoom lightbox. Arrows, swipe and Esc work. Placeholders are CSS shapes (data-shape + data-tone).
Carousel
sf-carousel with data-sf-carousel: scroll-snap, swipe or drag, arrows, dots, keyboard. data-sf-autoplay="4000" (pauses on hover and has a pause button), data-sf-loop, sf-carousel--multi.
Rating summary
data-sf-reviewsum with data-sf-counts (five stars first) builds the average and distribution bars. sf-stars shows any fractional --sf-rate on its own.
Leaderboard
data-sf-leaderboard sorts by data-score. Call Soft.leaderboard(el).setScores({id: score}) and rows glide to their new rank. The button here does it with random scores.
- Maya Okafor2,840
- Daniel Weiss2,410
- Sofia Ricci2,175
- Arjun Patel1,860
- Lena Fischer1,540
- Tomas Novak1,120
Metric tile grid / dashboard layout
sf-dash is a responsive grid (1, 2 then 4 columns). sf-tile holds any widget; span with sf-tile--w2, --w3, --w4, --h2.
Visitors
Last 12 weeks
Sources
Goals
Recent activity
- New design review9:41
- Importer merged8:15
- New teammateMon
The new empty states are lovely. Could we reuse the same illustration style on the 404 page?