Over budget
The fill is clamped to 100% in the partial.
stat
One number on a dashboard, with a label and how much it changed.
The big number
Put this inside <div rst-stats>.
<divrst-stat="lead">
<spanrst-stat-label>Revenue this month</span>
<spanrst-stat-num>€48,210</span>
<spanrst-stat-deltarst-tone="positive">+12%</span>
<spanrst-stat-note>vs. last month</span>
</div>
Put this inside <div rst-stats>.
{{template"stat"dict"Label""Revenue this month""Value""€48,210""Delta""+12%""Tone""positive""Note""vs. last month""Lead"true}}
Add Lead to one stat in the row to make it big. It is the same component, just larger.
You only need a label and a number. Everything else is optional.
When going down is good
Put this inside <div rst-stats>.
<divrst-stat>
<spanrst-stat-label>Time to first reply</span>
<spanrst-stat-num>1h 12m</span>
<spanrst-stat-deltarst-tone="positive">−38%</span>
<spanrst-stat-note>vs. last week</span>
</div>
Put this inside <div rst-stats>.
{{template"stat"dict"Label""Time to first reply""Value""1h 12m""Delta""−38%""Tone""positive""Note""vs. last week"}}
You set the colour, not the component. Here the number went down and that is good news, so the change is green.
When going up is bad
Put this inside <div rst-stats>.
<divrst-stat>
<spanrst-stat-label>Failed payments</span>
<spanrst-stat-num>9</span>
<spanrst-stat-deltarst-tone="negative">+3</span>
<spanrst-stat-note>vs. last week</span>
</div>
Put this inside <div rst-stats>.
{{template"stat"dict"Label""Failed payments""Value""9""Delta""+3""Tone""negative""Note""vs. last week"}}
Here the number went up and that is bad news, so the change is red.
Showing 4.1k instead of 4120? Put the full number in Exact. Screen readers only read what is on screen, so keep anything a person needs in the number itself.
person
Initials avatar, name and email. Quickly identifies people records.
Who did something, as words: a person's name, or the agent and the person it acted for. No badge and no icon.
An agent acting for a person
<spanrst-actor>Claude for Grace Hopper</span>
{{template"actor"dict"Actor".Actor}}
Set ui.ActorName once at boot to turn a subject into a name. The app itself, the zero Actor, renders nothing.
A person
<spanrst-actor>Grace Hopper</span>
{{template"actor"dict"Actor".Actor}}
callout
The one alert vocabulary: tinted strip, tone icon, optional bold title, one body paragraph.
info
<divrst-calloutrst-tone="info">
<spanrst-callout-icaria-hidden="true">
<svgclass="icon"viewBox="0 0 24 24"fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin="round"aria-hidden="true"><circlecx="12"cy="12"r="10"/><pathd="M12 16v-4"/><pathd="M12 8h.01"/></svg>
</span>
<divrst-callout-body>
<p>Posts are visible to members only until the site is published.</p>
</div>
</div>
{{template"callout"dict"Body""Posts are visible to members only until the site is published.""Tone""info"}}
positive
<divrst-calloutrst-tone="positive">
<spanrst-callout-icaria-hidden="true">
<svgclass="icon"viewBox="0 0 24 24"fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin="round"aria-hidden="true"><circlecx="12"cy="12"r="10"/><pathd="m9 12 2 2 4-4"/></svg>
</span>
<divrst-callout-body>
<strong>Payments are connected</strong>
<p>You can take payment for tickets now.</p>
</div>
</div>
{{template"callout"dict"Body""You can take payment for tickets now.""Title""Payments are connected""Tone""positive"}}
warning
<divrst-calloutrst-tone="warning">
<spanrst-callout-icaria-hidden="true">
<svgclass="icon"viewBox="0 0 24 24"fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin="round"aria-hidden="true"><pathd="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><pathd="M12 9v4"/><pathd="M12 17h.01"/></svg>
</span>
<divrst-callout-body>
<strong>Connect payments to start selling</strong>
<p>Your event is live but cannot take payment yet.</p>
</div>
</div>
{{template"callout"dict"Body""Your event is live but cannot take payment yet.""Title""Connect payments to start selling""Tone""warning"}}
negative
<divrst-calloutrst-tone="negative">
<spanrst-callout-icaria-hidden="true">
<svgclass="icon"viewBox="0 0 24 24"fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin="round"aria-hidden="true"><circlecx="12"cy="12"r="10"/><pathd="m15 9-6 6"/><pathd="m9 9 6 6"/></svg>
</span>
<divrst-callout-body>
<strong>The last import failed</strong>
<p>Nothing was changed. Fix row 91 and try again.</p>
</div>
</div>
{{template"callout"dict"Body""Nothing was changed. Fix row 91 and try again.""Title""The last import failed""Tone""negative"}}
A form's summary error line, role="alert". Takes a plain string; renders nothing when there is no error.
A rejected submission
<prst-form-errorrole="alert">That title is already taken.</p>
{{template"form-error""That title is already taken."}}
job-status
A background job's polled fragment. The data-poll attribute is emitted only while the job runs: leaving it out is how polling stops.
Running
<divrst-jobdata-poll="/jobs/1/fragment"data-poll-every="2">
<spanrst-spinaria-hidden="true"></span> <bdi><strong>Import</strong></bdi> is running: <bdi>128 of 400</bdi>…
<progressrst-job-barvalue="32"min="0"max="100"aria-hidden="true"></progress>
</div>
{{template"job-status"dict"Name""Import""Percent" 32
"PollSeconds" 2
"PollURL""/jobs/1/fragment""Progress""128 of 400""Status""running"}}
This one polls: it is the only sample on the page that asks the network for anything, and on a static site it simply never resolves.