Buttons
tier 2 — classes.btn is the base; every variant is one extra class. A panel's primary call to
action is always a filled button in its semantic colour.
Choose a variant by meaning, not appearance.
| Class | Use for |
|---|---|
.btn--brand.btn--solid | The neutral primary action |
.btn--go.btn--solid | Sends something outward — approve, apply, send, reroute |
.btn--warn.btn--solid | Changes who is in control — accept and take over |
.btn--warn | The same action as a secondary, beside a green primary |
.btn--danger | Destructive |
Tone and emphasis
A tone says what a button does — .btn--brand, --go, --warn,
--danger, --info, --secret — and an emphasis how loudly:
soft by default, .btn--solid filled, .btn--ghost with no fill until
hovered. Any tone takes any emphasis; a panel's one primary action is the filled one.
<div class="sedna-col sedna-gap-1">
<div class="sedna-row-wrap"><button class="btn" type="button">Neutral</button><button class="btn btn--solid" type="button">Neutral solid</button><button class="btn btn--ghost" type="button">Neutral ghost</button></div>
<div class="sedna-row-wrap"><button class="btn btn--brand" type="button">Publish</button><button class="btn btn--brand btn--solid" type="button">Publish</button><button class="btn btn--brand btn--ghost" type="button">Publish</button><button class="btn btn--brand btn--ghost btn--icon" type="button" aria-label="Publish"><i class="ri-arrow-right-line"></i></button></div>
<div class="sedna-row-wrap"><button class="btn btn--go" type="button">Approve</button><button class="btn btn--go btn--solid" type="button">Approve</button><button class="btn btn--go btn--ghost" type="button">Approve</button><button class="btn btn--go btn--ghost btn--icon" type="button" aria-label="Approve"><i class="ri-arrow-right-line"></i></button></div>
<div class="sedna-row-wrap"><button class="btn btn--warn" type="button">Take over</button><button class="btn btn--warn btn--solid" type="button">Take over</button><button class="btn btn--warn btn--ghost" type="button">Take over</button><button class="btn btn--warn btn--ghost btn--icon" type="button" aria-label="Take over"><i class="ri-arrow-right-line"></i></button></div>
<div class="sedna-row-wrap"><button class="btn btn--danger" type="button">Delete</button><button class="btn btn--danger btn--solid" type="button">Delete</button><button class="btn btn--danger btn--ghost" type="button">Delete</button><button class="btn btn--danger btn--ghost btn--icon" type="button" aria-label="Delete"><i class="ri-arrow-right-line"></i></button></div>
<div class="sedna-row-wrap"><button class="btn btn--info" type="button">Details</button><button class="btn btn--info btn--solid" type="button">Details</button><button class="btn btn--info btn--ghost" type="button">Details</button><button class="btn btn--info btn--ghost btn--icon" type="button" aria-label="Details"><i class="ri-arrow-right-line"></i></button></div>
<div class="sedna-row-wrap"><button class="btn btn--secret" type="button">Reveal key</button><button class="btn btn--secret btn--solid" type="button">Reveal key</button><button class="btn btn--secret btn--ghost" type="button">Reveal key</button><button class="btn btn--secret btn--ghost btn--icon" type="button" aria-label="Reveal key"><i class="ri-arrow-right-line"></i></button></div>
</div>
Variants
The full set, all at the same height.
<button class="btn">Neutral</button>
<button class="btn btn--brand btn--solid">Primary</button>
<button class="btn btn--go btn--solid"><i class="ri-check-line"></i> <span>Approve & send</span></button>
<button class="btn btn--warn btn--solid"><i class="ri-user-shared-line"></i> <span>Accept & take over</span></button>
<button class="btn btn--warn">Take over</button>
<button class="btn btn--danger"><i class="ri-delete-bin-line"></i> <span>Delete</span></button>
<button class="btn" disabled>Disabled</button>
Three sizes
.btn--sm, the default, and .btn--lg. Every control that can share a row
takes the same three heights — 28px, 36px and 44px — so a button, a link, an
icon button, a field and a chip line up; a badge does not, because it
has its own type scale.
<div class="sedna-col sedna-gap-2">
<div class="sedna-row-wrap">
<button class="btn btn--sm">Small</button>
<button class="btn btn--sm btn--brand btn--solid"><i class="ri-check-line"></i> <span>Small</span></button>
<button class="btn btn--sm btn--icon" aria-label="Small icon"><i class="ri-refresh-line"></i></button>
<span class="chip"><span class="chip-label">Small chip</span></span>
<a class="btn btn--sm" href="#">Small link</a>
</div>
<div class="sedna-row-wrap">
<button class="btn">Default</button>
<button class="btn btn--brand btn--solid"><i class="ri-check-line"></i> <span>Default</span></button>
<button class="btn btn--icon" aria-label="Default icon"><i class="ri-refresh-line"></i></button>
<span class="chip chip--lg"><span class="chip-label">Default chip</span></span>
<a class="btn" href="#">Default link</a>
</div>
<div class="sedna-row-wrap">
<button class="btn btn--lg">Large</button>
<button class="btn btn--lg btn--brand btn--solid"><i class="ri-check-line"></i> <span>Large</span></button>
<button class="btn btn--lg btn--icon" aria-label="Large icon"><i class="ri-refresh-line"></i></button>
<a class="btn btn--lg" href="#">Large link</a>
</div>
</div>
While its action runs
aria-busy="true" while a save or a call is in flight. The label stays in the layout
and is painted out, so the button keeps its measured width and does not shrink under the
cursor; a ring in the variant's own ink spins in its place, and a second pointer click is
ignored. Leave disabled off — it drops focus and stops the state being
announced — and have the handler ignore a second Enter while the work runs.
<div class="sedna-row-wrap">
<button class="btn btn--brand btn--solid" type="button">
<i class="ri-save-line"></i> <span>Save changes</span>
</button>
<button class="btn btn--brand btn--solid" type="button" aria-busy="true">
<i class="ri-save-line"></i> <span>Save changes</span>
</button>
<button class="btn btn--sm" type="button" aria-busy="true">Refresh</button>
</div>
Icon-only
.btn--icon is not optional — a bare .btn
keeps its text padding, so one glyph sits in a box half again as wide as it is tall. Give
every icon-only button an aria-label; the glyph itself is a bundled
Remix Icon, linked from
_content/Sedna.UI/lib/remixicon/remixicon.css as
ri-* on an <i>.
<button class="btn">Return to queue</button>
<button class="btn btn--icon" aria-label="Refresh" data-tip="Reload the list from the server."><i class="ri-refresh-line"></i></button>
<button class="btn btn--icon" aria-label="Copy link" data-tip="Copy a direct link to this item to the clipboard."><i class="ri-link"></i></button>
<button class="btn btn--icon btn--brand btn--solid" aria-label="Save"><i class="ri-save-line"></i></button>
<button class="btn btn--icon btn--sm" aria-label="Unpin"><i class="ri-pushpin-line"></i></button>
Ghost
.btn--ghost defers its border and fill until hover, for a dense row of
secondary actions — a table row's actions, a toolbar. It keeps the same box as a
bordered button, so a ghost and a solid button in one row still line up.
<button class="btn btn--ghost btn--icon" type="button" aria-label="More actions" data-tip="Rename, duplicate, export."><i class="ri-more-2-fill"></i></button>
<button class="btn btn--ghost" type="button"><i class="ri-eye-line"></i> <span>Preview</span></button>
<button class="btn btn--ghost btn--sm" type="button"><i class="ri-download-2-line"></i> <span>Export</span></button>
<button class="btn" type="button">Reassign</button>
In a line of text
.btn-bare is a <button> with no background, border or
padding, taking its font and colour from the text around it — for an identifier that
acts: a record number that opens the record, a key with a copy button beside it, a
chevron that unfolds a section. .btn-bare--link colours it like a link, for one
that goes somewhere.
Write it without .btn — it is the absence of the button's
chrome, not a variant of it, and both classes together bring the height and the hover fill
back. It keeps the library's focus ring, which is the declaration a hand-written inline reset
forgets: removing the border removes the browser's own outline with it. Tab through this
example to see it.
Reserved against order by Alex Fischer, four minutes ago.
Publishing key pk-live-8f2c4d
<div class="sedna-col sedna-gap-2" style="max-width:520px">
<p style="margin:0">
Reserved against order
<button class="btn-bare btn-bare--link" type="button">
<span>10482</span> <i class="ri-external-link-line" aria-hidden="true"></i>
</button>
by Alex Fischer, four minutes ago.
</p>
<p style="margin:0">
Publishing key <code>pk-live-8f2c4d</code>
<button class="btn-bare" type="button" data-copy="pk-live-8f2c4d" aria-label="Copy the publishing key">
<i class="ri-file-copy-line" aria-hidden="true" data-copied-hide></i>
<i class="ri-check-line" aria-hidden="true" data-copied-show="ok"></i>
</button>
</p>
<p style="margin:0">
<button class="btn-bare" type="button" aria-expanded="false">
<i class="ri-arrow-right-s-line" aria-hidden="true"></i> <span>Three earlier attempts</span>
</button>
</p>
</div>
A name that is read but not shown
.visually-hidden takes text out of the rendering and leaves it in the
accessibility tree — here the button shows a count and the hidden span says what the
count is of. Do not reach for display:none or a zero-size box instead: both
drop the element from the accessibility tree too.
<button class="btn">
<i class="ri-notification-3-line"></i> <span>12</span>
<span class="visually-hidden">unread notifications</span>
</button>
<a class="btn btn--brand btn--solid" href="#">
Continue <span class="visually-hidden">to the approval step</span>
</a>
As a link
.btn works on an <a> — it sets its own
text-decoration and colour, so no reset is needed.
<a class="btn" href="#"><i class="ri-external-link-line"></i> <span>Open in the warehouse</span></a>
<a class="btn btn--sm" href="#">Details</a>
A label on two lines
.btn--wrap lets the label wrap and starts it at the inline start, for a
picker whose choices are full-width buttons with a long name. A button is otherwise one line.
<div class="sedna-col sedna-gap-2" style="max-width:280px">
<button class="btn btn--wrap" type="button">
<i class="ri-user-line"></i>
<span>Alex Fischer<br><span class="text-muted text-sm">Northwind Retail, accounts payable and reconciliation</span></span>
</button>
<button class="btn btn--wrap" type="button">
<i class="ri-user-line"></i>
<span>Shared mailbox for the regional fulfilment team</span>
</button>
</div>
In a footer row
Cancel on the left of the primary, primary last — the reading order ends on the action.
<div class="modal-footer" style="width:100%; border-top:none; padding:0;">
<button class="btn">Cancel</button>
<button class="btn btn--go btn--solid"><i class="ri-send-plane-line"></i> <span>Approve & send</span></button>
</div>
Floating action button
.fab is one page-level action, pinned to a corner on a screen too small to show
a toolbar; .fab--icon is the circular,
label-in-an-aria-label form. Shown here position:static; in an app
it is fixed to the corner and must stay below every overlay.
<div class="sedna-row-wrap">
<button class="fab" type="button" style="position:static">
<i class="ri-add-line"></i> <span>New order</span>
</button>
<button class="fab fab--icon" type="button" style="position:static" aria-label="New order">
<i class="ri-add-line"></i>
</button>
</div>