Skip to content
Menu
Language, currently English
EnglishGaeilge简体中文Españolहिन्दीPortuguêsবাংলাРусский日本語廣東話Tiếng Việtالعربية

rastrillo design system

An overview of everything the design system provides. Theme: day. Language: English.

Display

The small pieces of vocabulary a screen is assembled from: status, identity, progress and the one alert shape.

Pre-built, consistent UI elements, rendered server-side.

The framework's own vocabulary calls these partials: ui.Templates() returns partials, and docs/site/templates.md documents them under that name. The word on this page changed; the code's did not.

Links here are inactive

Links inactive, sample source provided.

Each sample below in its own frame.

Sample content in English. Sample shells translated.

status-pill

A record's status as a tinted pill, colour and label.

Default tone (neutral)

Preview
<span rst-status rst-tone="neutral">Draft</span>

neutral

Preview
<span rst-status rst-tone="neutral">Draft</span>

positive

Preview
<span rst-status rst-tone="positive">Published</span>

warning

Preview
<span rst-status rst-tone="warning">Scheduled</span>

negative

Preview
<span rst-status rst-tone="negative">Failed</span>

badge

An uppercase bordered chip for small static markers. Distinct from status-pill, which is record status.

No tone (quiet default)

Preview
<span rst-badge>Draft</span>

neutral

Preview
<span rst-badge="neutral">Internal</span>

positive

Preview
<span rst-badge="positive">Live</span>

warning

Preview
<span rst-badge="warning">Beta</span>

negative

Preview
<span rst-badge="negative">Sold out</span>

meter

A capacity bar with its number.

Empty

Preview
<span rst-meter><meter rst-meter-bar value="0" min="0" max="100" aria-hidden="true"></meter><span rst-meter-num>0/500</span></span>

Part way

Preview
<span rst-meter><meter rst-meter-bar value="42" min="0" max="100" aria-hidden="true"></meter><span rst-meter-num>210/500</span></span>

Nearly full

Preview
<span rst-meter><meter rst-meter-bar value="82" min="0" max="100" aria-hidden="true"></meter><span rst-meter-num>412/500</span></span>

Full

Preview
<span rst-meter><meter rst-meter-bar value="100" min="0" max="100" aria-hidden="true"></meter><span rst-meter-num>500/500</span></span>

Over budget

Preview
<span rst-meter><meter rst-meter-bar value="100" min="0" max="100" aria-hidden="true"></meter><span rst-meter-num>700/500</span></span>

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

Preview
<div rst-stats><div rst-stat="lead"><span rst-stat-label>Revenue this month</span><span rst-stat-num>€48,210</span><span rst-stat-delta rst-tone="positive">&#43;12%</span><span rst-stat-note>vs. last month</span></div></div>

Add Lead to one stat in the row to make it big. It is the same component, just larger.

A smaller number

Preview
<div rst-stats><div rst-stat><span rst-stat-label>Unpaid invoices</span><span rst-stat-num>24</span></div></div>

You only need a label and a number. Everything else is optional.

When going down is good

Preview
<div rst-stats><div rst-stat><span rst-stat-label>Time to first reply</span><span rst-stat-num>1h 12m</span><span rst-stat-delta rst-tone="positive">−38%</span><span rst-stat-note>vs. last week</span></div></div>

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

Preview
<div rst-stats><div rst-stat><span rst-stat-label>Failed payments</span><span rst-stat-num>9</span><span rst-stat-delta rst-tone="negative">&#43;3</span><span rst-stat-note>vs. last week</span></div></div>

Here the number went up and that is bad news, so the change is red.

When you cannot say

Preview
<div rst-stats><div rst-stat><span rst-stat-label>Average session length</span><span rst-stat-num>4m 12s</span><span rst-stat-delta rst-tone="neutral">&#43;18s</span><span rst-stat-note>since Friday</span></div></div>

Leave the colour out and the change is grey. Do that when you cannot say if it is good or bad.

A shortened number

Preview
<div rst-stats><div rst-stat><span rst-stat-label>Messages sent</span><span rst-stat-num><data value="4120">4.1k</data></span></div></div>

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.

Name and email

Preview
<a rst-person href="/people/1"><span rst-person-av aria-hidden="true">G</span><span rst-person-meta><span rst-person-name>Grace Hopper</span><span rst-person-email>grace@example.com</span></span></a>

Large, the show-header size

Preview
<a rst-person="lg" href="/people/2"><span rst-person-av aria-hidden="true">A</span><span rst-person-meta><span rst-person-name>Ada Lovelace</span><span rst-person-email>ada@example.com</span></span></a>

No initial

Preview
<a rst-person href="/people/3"><span rst-person-av="empty" aria-hidden="true"></span><span rst-person-meta><span rst-person-name>Unclaimed invitation</span><span rst-person-email>invited@example.com</span></span></a>

callout

The one alert vocabulary: tinted strip, tone icon, optional bold title, one body paragraph.

Default tone (info), no title

Preview
<div rst-callout rst-tone="info"><span rst-callout-ic aria-hidden="true"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg></span><div rst-callout-body><p>Posts are visible to members only until the site is published.</p></div></div>

info

Preview
<div rst-callout rst-tone="info"><span rst-callout-ic aria-hidden="true"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg></span><div rst-callout-body><p>Posts are visible to members only until the site is published.</p></div></div>

positive

Preview
<div rst-callout rst-tone="positive"><span rst-callout-ic aria-hidden="true"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg></span><div rst-callout-body><strong>Payments are connected</strong><p>You can take payment for tickets now.</p></div></div>

warning

Preview
<div rst-callout rst-tone="warning"><span rst-callout-ic aria-hidden="true"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="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"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg></span><div rst-callout-body><strong>Connect payments to start selling</strong><p>Your event is live but cannot take payment yet.</p></div></div>

negative

Preview
<div rst-callout rst-tone="negative"><span rst-callout-ic aria-hidden="true"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg></span><div rst-callout-body><strong>The last import failed</strong><p>Nothing was changed. Fix row 91 and try again.</p></div></div>

negative, announced as an alert

Preview
<div rst-callout rst-tone="negative" role="alert"><span rst-callout-ic aria-hidden="true"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg></span><div rst-callout-body><strong>The import stopped</strong><p>Nothing was changed. Fix row 91 and try again.</p></div></div>

Alert adds role="alert" to display important messages.

detail-list

Definition list about a record on a detail screen. Mono marks for machine-ish values.

Four facts, one machine-ish

Preview
<section rst-box><dl rst-detail>
  <dt>Audience</dt>
  <dd>Members</dd>
  <dt>Main page</dt>
  <dd>No</dd>
  <dt>Published</dt>
  <dd><time datetime="2026-08-02">2 August 2026</time></dd>
  <dt>Reference</dt>
  <dd class="rst-mono">post_01H9ZQ</dd>
</dl></section>

notice

A one-line confirmation after a redirect. Takes a plain string, not a dict, and renders nothing for an empty one.

A saved message

Preview
<p rst-notice role="status">Post saved.</p>

form-error

A form's summary error line, role="alert". Takes a plain string; renders nothing when there is no error.

A rejected submission

Preview
<p rst-form-error role="alert">That title is already taken.</p>

job-status

A background job's polled fragment. The data-poll attribute is emitted only while the job runs — omitting it is how polling stops.

Running

Preview

<div rst-job data-poll="/jobs/1/fragment" data-poll-every="2">
  <span rst-spin aria-hidden="true"></span> <strong>Import</strong> is running — 128 of 400…
  <progress rst-job-bar value="32" min="0" max="100" aria-hidden="true"></progress>
</div>

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.

Finished

Preview

<div rst-job>
  <strong>Import</strong> finished.
</div>

Failed

Preview

<div rst-job>
  <strong>Import</strong> failed: row 91: no such column &#34;published&#34;
</div>