Connection lost. Reconnecting… attempt 1 of 8
Paused. Your work is held on the server.
Could not reconnect.
This session has expired on the server.
DR.Simple_UI
Showing main. This can be ahead of the version your app has installed — check what a class says it needs before copying it. Releases (opens in a new tab)

Media and prose

tier 2 — classes

Content the app did not author: an attachment, an article body, or a value the reader is not allowed to see.

Media frame

A bounded box for an image or embed whose size you do not control. aspect-ratio plus object-fit:contain is what stops the page reflowing as images arrive — the box has its height before the image loads.

contain rather than cover, because these are documents and cropping a screenshot removes the part somebody needed. .media-frame--cover is there for a decorative banner, where cropping is the right answer. Use <figure> with .media-figure when there is a caption — an image whose meaning is in its caption still needs a real alt.

<div class="gallery" style="max-width:520px">
    <figure class="media-figure">
        <div class="media-frame media-frame--square">
            <i class="ri-image-line" style="font-size:28px; color:var(--border-hover)"></i>
        </div>
        <figcaption>Square — a thumbnail</figcaption>
    </figure>
    <figure class="media-figure">
        <div class="media-frame">
            <i class="ri-image-line" style="font-size:28px; color:var(--border-hover)"></i>
        </div>
        <figcaption>16:10 — the default</figcaption>
    </figure>
    <figure class="media-figure">
        <div class="media-frame media-frame--wide">
            <i class="ri-image-line" style="font-size:28px; color:var(--border-hover)"></i>
        </div>
        <figcaption>21:9 — a banner</figcaption>
    </figure>
</div>

Prose

Long-form text rendered from a source the app does not control — a release note, a knowledge-base article, an e-mail body. .markdown-body already covers rendered Markdown; .prose is the same job when the HTML did not come from Markdown. They look identical, so an app has one typographic voice rather than two.

The measure is capped at 72 characters. Past roughly that the eye loses the line it is returning to, which no amount of line-height fixes. A table inside untrusted prose gets display:block; overflow-x:auto, because its own content sets its minimum width and it is the one thing that will otherwise break the page.

Release 0.4.0

This release adds the overlay family and the collection classes. Nothing was renamed, so an upgrade needs no app changes.

Every class name added is listed below, so you can grep your own stylesheets before bumping.
  • .drawer and .sheet
  • .palette, .spotlight-hole
<div class="prose">
    <h2>Release 0.4.0</h2>
    <p>
        This release adds the overlay family and the collection classes. Nothing was renamed,
        so an upgrade needs no app changes.
    </p>
    <blockquote>Every class name added is listed below, so you can grep your own
    stylesheets before bumping.</blockquote>
    <ul>
        <li><code>.drawer</code> and <code>.sheet</code></li>
        <li><code>.palette</code>, <code>.spotlight-hole</code></li>
    </ul>
</div>

Redacted values

A value deliberately withheld — a secret, a masked identifier, a field the reader's role cannot see.

It must not merely look hidden. A blur or a low opacity leaves the real text in the DOM, where it is readable by view-source, by a screen reader, and by anyone who selects it. This class marks a placeholder the server sent in place of the value. The value never reaches the browser. If it is in the HTML, it is not redacted, whatever it looks like.

Client IDorders-console-01
Client secret not shown
Salary band requires HR role
<div class="card" style="max-width:420px">
    <div class="card-body">
        <div class="kv"><span class="k">Client ID</span><span class="v">orders-console-01</span></div>
        <div class="kv">
            <span class="k">Client secret</span>
            <span class="redacted"><i class="ri-eye-off-line"></i> not shown</span>
        </div>
        <div class="kv">
            <span class="k">Salary band</span>
            <span class="redacted"><i class="ri-lock-line"></i> requires HR role</span>
        </div>
    </div>
</div>

.gallery is a breakpoint-free grid of thumbnails. Each tile is a real <button> or <a> directly inside it — never a <div> with a click handler — and the stylesheet gives the tile's hover and focus ring to the .media-frame inside it.

Inside the gallery every frame is square whatever aspect modifier it carries, so a row of mixed attachments lines up. The file name is part of the tile, because an icon does not say which document it is.

<div class="gallery" style="max-width:520px">
    <button class="btn-ghost" type="button" style="padding:0; text-align:start">
        <span class="media-frame">
            <i class="ri-file-pdf-2-line" style="font-size:26px; color:var(--border-hover)"></i>
        </span>
        <span class="text-sm text-muted text-truncate dr-mt-1">pod-ord-4209.pdf</span>
    </button>
    <button class="btn-ghost" type="button" style="padding:0; text-align:start">
        <span class="media-frame">
            <i class="ri-image-line" style="font-size:26px; color:var(--border-hover)"></i>
        </span>
        <span class="text-sm text-muted text-truncate dr-mt-1">pallet-label.png</span>
    </button>
    <button class="btn-ghost" type="button" style="padding:0; text-align:start">
        <span class="media-frame">
            <i class="ri-mail-line" style="font-size:26px; color:var(--border-hover)"></i>
        </span>
        <span class="text-sm text-muted text-truncate dr-mt-1">customer-reply.eml</span>
    </button>
    <button class="btn-ghost" type="button" style="padding:0; text-align:start">
        <span class="media-frame">
            <i class="ri-file-excel-2-line" style="font-size:26px; color:var(--border-hover)"></i>
        </span>
        <span class="text-sm text-muted text-truncate dr-mt-1">stock-check.xlsx</span>
    </button>
</div>