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.
An unhandled error has occurred.
Sedna.UI
v0.17.0 · main

Ranges and steppers

tier 2 — classes

The controls whose native internals have to be named per engine. Everything here restates one design in several vendor pseudo-elements. Date and time inputs, the other such family, have a page of their own.

One rule per engine, never a shared list The two engines expose different pseudo-elements and cannot be combined into one selector list: an unknown pseudo-element invalidates the whole rule, so a shared ::-webkit-…, ::-moz-… list applies in neither browser. Write one rule per engine.

Range

appearance: none removes the whole native widget, track included, so both are drawn here.

A range gives no readout. Put the value in text beside it with .form-range-value — the thumb position is not a number, and it is unreadable to a screen reader on its own. The readout is fixed-width and tabular, so the track does not shift while dragging.

85%

Reservations below this are held for a human decision.

<div class="form-field" style="max-width:420px">
    <label class="form-label" for="r-conf">Confidence threshold</label>
    <div class="sedna-row">
        <input class="form-range" id="r-conf" type="range" min="0" max="100" value="85" />
        <span class="form-range-value">85%</span>
    </div>
    <p class="form-hint">Reservations below this are held for a human decision.</p>
</div>

Stepper

For a value adjusted one at a time. The native spinner is tiny, inconsistent between engines, and invisible until hover in some — so it is removed and replaced with two real buttons, which are also a usable size on touch.

Give each button an aria-label: + and are announced as “plus” and “minus” without saying what of. Hiding the native spinner needs both the Firefox property and the WebKit pseudo-element; neither implies the other.

<div class="form-field" style="max-width:220px">
    <label class="form-label" for="s-retry">Retry attempts</label>
    <div class="stepper">
        <button class="btn" type="button" aria-label="One fewer retry">&minus;</button>
        <input class="form-input" id="s-retry" type="number" value="3" min="0" max="9" />
        <button class="btn" type="button" aria-label="One more retry">+</button>
    </div>
</div>

Three sizes

The stepper takes its tier from its children: .btn-sm on both buttons and .form-input-sm on the input.

Every row here is one control height, so the stepper, the date field and the button beside them agree at each size. Mixing tiers within a row is the one thing that makes a filter bar look assembled by accident.

<div class="sedna-col sedna-gap-2">
    <div class="sedna-row-wrap">
        <div class="stepper">
            <button class="btn btn-sm" type="button" aria-label="One fewer retry">&minus;</button>
            <input class="form-input form-input-sm" type="number" value="3" min="0" max="9" aria-label="Retry attempts, small" />
            <button class="btn btn-sm" type="button" aria-label="One more retry">+</button>
        </div>
        <input class="form-input form-input-sm" type="date" value="2026-07-31" aria-label="Active from, small" />
        <button class="btn btn-sm" type="button">Apply</button>
    </div>
    <div class="sedna-row-wrap">
        <div class="stepper">
            <button class="btn" type="button" aria-label="One fewer retry">&minus;</button>
            <input class="form-input" type="number" value="3" min="0" max="9" aria-label="Retry attempts" />
            <button class="btn" type="button" aria-label="One more retry">+</button>
        </div>
        <input class="form-input" type="date" value="2026-07-31" aria-label="Active from" />
        <button class="btn" type="button">Apply</button>
    </div>
    <div class="sedna-row-wrap">
        <div class="stepper">
            <button class="btn btn-lg" type="button" aria-label="One fewer retry">&minus;</button>
            <input class="form-input form-input-lg" type="number" value="3" min="0" max="9" aria-label="Retry attempts, large" />
            <button class="btn btn-lg" type="button" aria-label="One more retry">+</button>
        </div>
        <input class="form-input form-input-lg" type="date" value="2026-07-31" aria-label="Active from, large" />
        <button class="btn btn-lg" type="button">Apply</button>
    </div>
</div>