Switch
En avkryssingsboks med role="switch". Skjermlesere sier da «på» og «av» framfor «avkrysset», mens tastaturet og FormData virker som for en vanlig boks.
Velg Switch når innstillingen trer i kraft med det samme. Skal valget først gjelde når skjemaet sendes inn, er Checkbox riktig: en bryter som ikke gjør noe før du trykker «Lagre» lover mer enn den holder.
Slik tar du den i bruk
Section titled “Slik tar du den i bruk”<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/tokens/tokens.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/components/css/switch/switch.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/components/css/label/label.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/src/components/css/help-text/help-text.css"><!-- Eller alt i én fil: https://cdn.jsdelivr.net/npm/@fristil/designsystem@0.27.1/dist/fristil.css --><div class="fs-switch-row"><input class="fs-switch" type="checkbox" role="switch" id="epost" checked /><label class="fs-label" for="epost">Varsle meg på e-post</label></div>
<div class="fs-switch-row"><input class="fs-switch" type="checkbox" role="switch" id="sms" /><label class="fs-label" for="sms">Varsle meg på SMS</label></div>
<div class="fs-switch-row"><input class="fs-switch" type="checkbox" role="switch" id="brev" disabled /><label class="fs-label" for="brev">Varsle meg i posten</label></div>import "@fristil/designsystem/tokens.css"import "@fristil/designsystem/switch.css"import "@fristil/designsystem/label.css"import "@fristil/designsystem/help-text.css"fs brukes på to måter, og hvilken avhenger av om du lager elementet eller finner det.
Lager du markupen, sprer du attributtene inn. Det er veien i React, Astro og alt annet som rendrer:
import { fs } from "@fristil/designsystem/react"
<div className={fs.switch.row}> <input {...fs.switch()} id="varsler" /> <label {...fs.label()} htmlFor="varsler">Varsle meg på e-post</label></div>Importen går til /react her, siden blokka er JSX. Derfra heter nøklene className og htmlFor. I Astro og alt annet uten React importerer du @fristil/designsystem og får class og for.
Står elementet der fra før, setter du dem på det. Det er veien når du forbedrer HTML en server eller en mal har sendt:
import { fs } from "@fristil/designsystem"
const bryter = document.querySelector<HTMLInputElement>("#varsler")
// Slå av mens lagringen går, så brukeren ikke rekker å trykke to ganger.fs.setAttributes(bryter, fs.switch({ disabled: true }))
// Og på igjen når svaret er inne.fs.setAttributes(bryter, fs.switch())Funksjonen setter både type og role, som er de to tingene som må stå sammen for at bryteren skal leses opp riktig. fs.switch.row gir klassen på raden rundt.
Importerer du den direkte i stedet for gjennom fs, heter den switchControl, siden switch er et reservert ord i JavaScript:
import { switchControl } from "@fristil/designsystem"Lagring med en gang
Section titled “Lagring med en gang”Bryteren lover at endringen gjelder. Da må den også si fra når lagringen feiler, og gå tilbake. Markupen er den samme i «Ren HTML» og Astro; React bruker byggefunksjonene, og Datastar sine egne attributter. Astro bruker det samme skriptet som «Ren HTML».
<div class="fs-switch-row"> <input class="fs-switch" type="checkbox" role="switch" id="varsler" /> <label class="fs-label" for="varsler">Varsle meg på e-post</label></div><p class="fs-help-text" id="varsler-status" role="status"></p>
<script type="module"> const bryter = document.getElementById("varsler") const status = document.getElementById("varsler-status")
bryter.addEventListener("change", async () => { const pa = bryter.checked bryter.disabled = true
try { await fetch("/api/varsler", { method: "PUT", headers: { "content-type": "application/json" }, body: JSON.stringify({ epost: pa }), }) status.textContent = pa ? "Varsler er på." : "Varsler er av." } catch { bryter.checked = !pa status.textContent = "Klarte ikke å lagre. Prøv igjen." } finally { bryter.disabled = false } })</script>import { useState } from "react"import { fs } from "@fristil/designsystem/react"
export function Varslingsbryter({ start }: { start: boolean }) { const [pa, settPa] = useState(start) const [lagrer, settLagrer] = useState(false) const [status, settStatus] = useState("")
async function endret(nyVerdi: boolean) { // Slå av med en gang, så bryteren ikke henger etter fingeren. settPa(nyVerdi) settLagrer(true) settStatus("")
try { await fetch("/api/varsler", { method: "PUT", headers: { "content-type": "application/json" }, body: JSON.stringify({ epost: nyVerdi }), }) settStatus(nyVerdi ? "Varsler er på." : "Varsler er av.") } catch { // Tilbake dit den var. Bryteren lovet noe den ikke holdt. settPa(!nyVerdi) settStatus("Klarte ikke å lagre. Prøv igjen.") } finally { settLagrer(false) } }
return ( <> <div className={fs.switch.row}> <input {...fs.switch()} id="varsler" checked={pa} disabled={lagrer} onChange={(e) => endret(e.currentTarget.checked)} /> <label {...fs.label()} htmlFor="varsler">Varsle meg på e-post</label> </div> <p {...fs.helpText()} role="status">{status}</p> </> )}checked og onChange sammen gjør feltet kontrollert, og det er nettopp det som gjør tilbakerullingen mulig: React tegner bryteren etter tilstanden din, ikke etter det brukeren klikket.
<!-- Datastar selv. Uten den gjør `data-`-attributtene under ingenting. --><script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar.js"></script>
<div class="fs-switch-row" data-signals="{varsler: false, lagrer: false, status: ''}"> <input class="fs-switch" type="checkbox" role="switch" id="varsler" data-bind:varsler data-attr:disabled="$lagrer" data-on:change="@put('/api/varsler')" /> <label class="fs-label" for="varsler">Varsle meg på e-post</label></div><p class="fs-help-text" role="status" data-text="$status"></p>Serveren eier utfallet her. @put sender signalene, og svaret setter status og, når lagringen feilet, varsler tilbake dit den var. Tilbakerullingen står altså i serveren og ikke i siden, som for all annen tilstand serveren eier.
role="status" gjør at skjermlesere leser opp resultatet uten å avbryte det brukeren holder på med.
Klasser du kan style
Section titled “Klasser du kan style”| Klasse | Hva det er |
|---|---|
.fs-switch | Selve bryteren |
.fs-switch-row | Raden som holder bryteren og teksten ved siden av hverandre |
| Variabel | Standard |
|---|---|
--fs-switch-width | var(--fs-spacing-10) |
--fs-switch-height | var(--fs-spacing-6) |
Knappen inni er en gradient og ikke et pseudoelement, fordi Firefox ikke rendrer ::before og ::after på et <input>. Den følger derfor høyden på bryteren av seg selv. Se Tilpasning.
Bryteren glir mellom av og på. Har brukeren bedt om mindre bevegelse i systemet sitt, bytter den i stedet tilstand uten overgang.
Tilgjengelighet
Section titled “Tilgjengelighet”- Ledeteksten skal si hva bryteren styrer, ikke hvilken tilstand den er i. «Varsle meg på e-post», ikke «E-postvarsler på».
- Ikke skriv «Av» og «På» som tekst ved siden av. Skjermleseren sier det allerede, og teksten blir motsatt av seg selv når brukeren slår den om.
- Bryteren har ingen ugyldig tilstand. Er det påkrevd å slå den på, for eksempel for å godta vilkår, hører det hjemme i en Checkbox med
required. - Trenger endringen bekreftelse eller kan den ikke angres, bruk en knapp i stedet. En bryter som åpner en dialog er ikke en bryter.