Formulär
Kontrollerna är stilade som element. Klasserna är för undantagen.
Kontroller
<input type="text" />
<select>…</select>
<textarea></textarea>Chevronen är en token
En bakgrundsbild kan inte läsacurrentColor, så chevronens URL är en token per tema.
Fält
Etikett, kontroll, sedan hjälptext eller fel.
Börja skriva för att söka bland 87 kunder.
<Field id="customer" label="Kund" hint="Börja skriv för att söka.">
<input type="text" id="customer" />
</Field>placeholder är inte en etikett
Den försvinner när man börjar skriva — precis när man behöver den.Sammansatta
Ett affix svetsat till kontrollen. En ram runt paret, inte två som nuddar.
<div class="ws-input-group">
<span class="ws-input-group__affix"><Icon name="Search" /></span>
<input type="search" />
</div>Val
<label class="ws-check"><input type="checkbox" /> Etikett</label>
<label class="ws-switch"><input type="checkbox" /> Etikett</label>Switch eller kryssruta
Switch för något som slår igenom direkt. Behöver det ett Spara är det en kryssruta.Fel
aria-invalid på kontrollen, inte en klass — CSS:en läser det skärmläsaren läser.
Fel: Måste vara mellan 0 och 24.
Fel: Adressen saknar en domän.
<Field id="hours" label="Timmar" error="Måste vara mellan 0 och 24.">
<input type="number" id="hours" value="31" />
</Field>Felsammanfattning
Som GOV.UK: överst i ett formulär som inte gick igenom, varje fel en länk till sitt fält. Den tar fokus när den visas, och länken flyttar fokus till fältet med etiketten synlig.
Det finns ett problem
<ErrorSummary errors={[
{ href: "#hours", text: "Timmar måste vara mellan 0 och 24" },
{ href: "#email", text: "E-postadressen saknar en domän" },
]} />
<!-- utan komponenten -->
<div class="ws-error-summary" data-malm-error-summary tabindex="-1">
<div role="alert">
<h2 class="ws-error-summary__title">Det finns ett problem</h2>
<ul class="ws-error-summary__list">
<li><a href="#hours">Timmar måste vara mellan 0 och 24</a></li>
</ul>
</div>
</div>Felmeddelandet i sammanfattningen och vid fältet är samma mening. Ge sidans titel Fel: först, så att det hörs innan något annat.
Teckenräknare
Som GOV.UK: hur många tecken som är kvar, under fältet. Över gränsen blir räknaren ett fel, men texten går att skriva klart och korta sedan.
Vad gjordes, och för vem?
Du kan skriva upp till 200 tecken
<Field id="summary" label="Sammanfattning" hint="Vad gjordes, och för vem?" maxlength={200}>
<textarea id="summary" rows="4"></textarea>
</Field>Layout
Fältrader kollapsar på en container query, inte en viewport-query.
<div class="ws-field-row">…</div>ws-field--wide tar hela fältraden, för en textruta eller den enda inställning som behöver platsen. ws-field--narrow är för ett kort värde — ett antal dagar, en kod — som i full bredd läses som en mening.
<div class="ws-field-row">
<label class="ws-field ws-field--narrow">…</label>
<label class="ws-field ws-field--wide">…<textarea></textarea></label>
</div>Tidfält
Dagens ena kontroll: stor, högerställd mot sin enhet, och tabulär så att en kolumn av dem linjerar.
Ett dygn är 24 timmar.
h<Field id="hours" label="Arbetad tid" hint="Ett dygn är 24 timmar.">
<span class="ws-input-group ws-input-group--hours">
<input type="number" id="hours" step="0.5" min="0" max="24" value="7.5" />
<span class="ws-input-group__affix">h</span>
</span>
</Field>Grupp av val
Flera kontroller under en fråga, som GOV.UK: legend är frågan, och ledtråden och felet beskriver hela gruppen. ws-field__value är ett värde där ett fält annars skulle stå.
<Fieldset id="scopes" legend="Behörigheter" hint="Välj minst en.">
<label class="ws-check"><input type="checkbox" name="scope" value="read" /> Läsa</label>
…
</Fieldset>
<Fieldset legend="Länkar" gap={4}>…fält…</Fieldset>
<div class="ws-field">
<span class="ws-field__label">Kund-ID</span>
<p class="ws-field__value">K-1042</p>
</div>Filter
Ett filter är en del av adressen. Ett fält med form är ett eget GET-formulär som bär sidans övriga parametrar, och en lista med autosubmit skickar det när den ändras; utan skript finns knappen Visa. Flera värden i ett filter är MultiSelect med picker: knappen säger det enda valet, eller filtret och hur många.
<Field id="f-kund" label="Kund" class="ws-field--auto" form={{ hidden: [["period", "2026-10-01"]] }}>
<select id="f-kund" name="kund" data-malm-autosubmit data-malm-drop-empty>
<option value="">Alla</option>…
</select>
</Field>
field({ …, form: { hidden }, controlHtml: select({ autosubmit: true, options, attrs: { id, name } }) })
<form method="get" class="ws-cluster">
<MultiSelect picker id="f-ansvarig" label="Ansvarig" name="ansvarig"
options={personer} selected={["anna", "bo"]} />
</form>Fil
Plattformens filfält, med knappen ritad som en sekundär knapp. Filnamnet och dialogen är webbläsarens.
<Field id="logo" label="Logotyp"><input type="file" id="logo" name="logo" accept="image/*" /></Field>Sökfält med förslag
Skriv, se vad som matchar, välj ett. En riktig combobox: piltangenter, Enter, Esc — och hörbar.
- Ärenden
- #2853Ny webbplats, etapp 2
- #2847Formulär som inte skickas
- Projekt
- INT-FIntern tid
- SK07Löpande arbete
Inget hittat
<div class="ws-combobox" id="ticket" data-malm-combobox>
<label class="ws-sr-only" for="ticket-input">Sök ärende</label>
<input type="text" id="ticket-input" placeholder="Sök ärende" data-combobox-input />
<div class="ws-popover-panel ws-combobox__panel" data-combobox-panel hidden>
<ul class="ws-combobox__list" data-combobox-list>
<li role="none"><ul class="ws-combobox__section" role="group" aria-labelledby="g1">
<li class="ws-combobox__group" role="presentation" id="g1" data-combobox-group>Ärenden</li>
<li class="ws-combobox__option" role="option" data-value="ticket:2853"
data-search="2853 Whitespace Ny webbplats">…</li>
</ul></li>
</ul>
<p class="ws-combobox__empty" data-combobox-empty hidden>Inget hittat</p>
</div>
</div>
<!-- valet är produktens: -->
combobox.addEventListener("malm:select", (event) => event.detail.value);Flera värden
Valen som taggar och ett fält att söka bland resten. Under ligger en riktig <select multiple>: det är den formuläret skickar, och den som syns utan skript. Backsteg i ett tomt fält tar bort den sista. Samma MultiSelect som filtrets, utan picker.
Sök och välj flera.
<Field id="repos" label="Ytterligare GitHub-repositories" hint="Sök och välj flera." optional>
<MultiSelect id="repos" name="github_repo_ids" placeholder="Sök repository"
options={repos} selected={valda} />
</Field>
<!-- produkten styr valen genom selecten -->
option.toggleAttribute("data-combobox-excluded", true); option.selected = false;
refreshCombobox(combobox);