Rammeverk
CSS-komponentene er klasser og krever ingenting av rammeverket. Web-komponentene trenger av og til oppsett, og denne siden samler det.
Alle web-komponentene registreres på samme måte, og hver av dem har sin egen side med et eksempel i alle fire miljøene: Field, Tabs, Error Summary, Popover, Suggestion, Toast, Session Timeout og Connection Status.
Tre ting gjelder overalt:
define-funksjonen må kjøre én gang når appen starter, før elementet brukes.- Boolske attributter er sanne så lenge de finnes.
invalid="false"gjør feltet ugyldig. Skal attributtet bort, må det fjernes helt. - Serveren skriver markupen, komponenten fester oppførsel. Se Markup og oppførsel for hvorfor, og hva det betyr i hvert av miljøene.
React har i tillegg @fristil/designsystem/react, som gir className og htmlFor. Uten den skriver React «Invalid DOM property» i konsollen for hvert element. De andre bruker HTML-navnene direkte.
Ren HTML
Section titled “Ren HTML”Ingen byggverktøy, ingen pakkebehandler i nettleseren.
<!doctype html><html lang="nb"> <head> <link rel="stylesheet" href="/node_modules/@fristil/designsystem/src/tokens/tokens.css" /> <link rel="stylesheet" href="/node_modules/@fristil/designsystem/src/components/ramme/field/field.css" /> </head> <body> <form id="skjema"> <fs-field required-marker="symbol"> <label>Fullt navn</label> <input class="fs-input" type="text" name="navn" required /> <p class="fs-error-text">Fyll inn navnet ditt.</p> </fs-field>
<button class="fs-button" type="submit">Send</button> </form>
<script type="module"> import { defineFsField } from "/node_modules/@fristil/designsystem/dist/components/ramme/field/fs-field.js" defineFsField()
document.getElementById("skjema").addEventListener("submit", (hendelse) => { hendelse.preventDefault() console.log(Object.fromEntries(new FormData(hendelse.currentTarget))) }) </script> </body></html>new FormData(...) plukker opp feltet uten videre, fordi <fs-field> holder elementene i vanlig DOM.
CSS-komponentene krever ikke engang skriptet:
<link rel="stylesheet" href="@fristil/designsystem/tokens.css" /><link rel="stylesheet" href="@fristil/designsystem/button.css" />
<button class="fs-button" data-variant="secondary">Lagre utkast</button>Dette er delen som overlever lengst. Klassen og dataattributtet er en kontrakt nettleseren forstår direkte.
import "@fristil/designsystem/tokens.css"import "@fristil/designsystem/field.css"import "@fristil/designsystem/suggestion.css"
import { defineFsField } from "@fristil/designsystem/field"import { defineFsSuggestion } from "@fristil/designsystem/suggestion"
defineFsField()defineFsSuggestion()Bruker du CSS-komponentene, importer fs fra React-inngangen:
import { fs } from "@fristil/designsystem/react"
<button {...fs.button({ variant: "secondary" })}>Lagre utkast</button>Importerer du dette i main.tsx før createRoot, er elementene registrert før React rekker å tegne noe.
Importer typene for de egendefinerte elementene én gang. Legg importen i en .d.ts-fil, så havner den aldri i bygget:
import "@fristil/designsystem/react-jsx"Uten den kjenner ikke TypeScript <fs-field> i det hele tatt:
Property 'fs-field' does not exist on type 'JSX.IntrinsicElements'Med den får du autofullføring og feilmelding på attributtene:
<fs-field required-marker="tekst" /> // feil: "none" | "symbol" | "text"<fs-session-timeout warnAt={1500} /> // feil: attributtet heter warn-at<fs-connection-status offline="Nede" /> // feil: ukjent attributt// main.tsx, kjøres én gang når appen starterimport { defineFsField } from "@fristil/designsystem/field"import "@fristil/designsystem/field.css"
defineFsField()// src/fristil.d.ts, gir <fs-field> typer i JSXimport "@fristil/designsystem/react-jsx"import { fs } from "@fristil/designsystem/react"import { useState } from "react"
export function Kontaktskjema() { const [navn, setNavn] = useState("") const [berørt, setBerørt] = useState(false)
const ugyldig = berørt && navn.trim() === ""
return ( <form onSubmit={(e) => e.preventDefault()}> <fs-field required-marker="symbol" invalid={ugyldig || undefined}> <label>Fullt navn</label> <input {...fs.input({ type: "text" })} name="navn" value={navn} onChange={(e) => setNavn(e.target.value)} onBlur={() => setBerørt(true)} /> <p {...fs.errorText()}>Fyll inn navnet ditt.</p> </fs-field>
<button {...fs.button()} type="submit">Send</button> </form> )}En .astro-fil er HTML med frontmatter over. Stilarkene importeres der, og fs brukes rett i malen, siden Astro støtter spredning som JSX.
---import { fs } from "@fristil/designsystem"import "@fristil/designsystem/tokens.css"import "@fristil/designsystem/button.css"import "@fristil/designsystem/badge.css"---
<button {...fs.button({ variant: "secondary" })}>Lagre utkast</button><span {...fs.badge({ color: "success" })}>Innvilget</span>Kjøres ved bygging. Ut kommer ren HTML:
<button class="fs-button" data-variant="secondary">Lagre utkast</button><span class="fs-badge" data-color="success">Innvilget</span>Null JavaScript sendt til nettleseren. fs er borte når siden er bygget.
Felt uten JavaScript
Section titled “Felt uten JavaScript”fs.field() regner ut koblingen i frontmatteret, så den også blir statisk HTML:
---import { fs } from "@fristil/designsystem"import "@fristil/designsystem/tokens.css"import "@fristil/designsystem/field.css"
const epost = fs.field({ id: "epost", required: "symbol", help: true, error: true })---
<label {...epost.label}>E-postadresse</label><input {...fs.input({ type: "email" })} {...epost.control} name="epost" required /><p {...fs.helpText()} {...epost.help}>Vi sender kvittering hit.</p><p {...fs.errorText()} {...epost.error}>Skriv en gyldig adresse.</p>Ingen <fs-field>, ingen kjøretid.
Web-komponenter i Astro
Section titled “Web-komponenter i Astro”Skal feltet kunne bli ugyldig mens brukeren står i det, må komponenten registreres. Astro pakker <script>-tagger og kjører dem på klienten:
---import "@fristil/designsystem/tokens.css"import "@fristil/designsystem/field.css"---
<fs-field required-marker="symbol"> <label>Fullt navn</label> <input class="fs-input" type="text" name="navn" required /> <p class="fs-error-text">Fyll inn navnet ditt.</p></fs-field>
<script> import { defineFsField } from "@fristil/designsystem/field" defineFsField()</script>customElements finnes bare i nettleseren, så registreringen kan ikke stå i frontmatteret. Et <script> i malen er alt som skal til: komponentene er vanlige egendefinerte elementer, og trenger verken en Astro-integrasjon eller et client:-direktiv.
Astro og Datastar
Section titled “Astro og Datastar”Astro bygger HTML-en, Datastar gir den oppførsel, og ingen av delene krever en komponentmodell i nettleseren.
HTML med Datastar
Section titled “HTML med Datastar”Datastar legger reaktivitet på vanlig HTML med data-*-attributter. Ett skript, ingen byggesteg. Samme premiss som Fristil.
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.3/bundles/datastar.js"></script><form data-signals="{navn: '', beroert: false}" data-computed:ugyldig="$beroert && $navn.trim() === ''"> <fs-field required-marker="symbol" data-attr:invalid="$ugyldig"> <label>Fullt navn</label> <input class="fs-input" type="text" name="navn" data-bind:navn data-on:blur="$beroert = true" /> <p class="fs-error-text">Fyll inn navnet ditt.</p> </fs-field>
<button class="fs-button" type="submit">Send</button></form>
<script type="module"> import { defineFsField } from "@fristil/designsystem/field" defineFsField()</script>Tre attributter gjør hele jobben:
data-signalsoppretter tilstanden.data-computed:ugyldigutleder valideringen av den.data-bind:navnbinder feltet begge veier, ogdata-on:blurmarkerer at brukeren har forlatt det.
data-attr:invalid knytter Datastar til komponenten: den setter attributtet når uttrykket er sant og fjerner det når det er usant, nøyaktig slik <fs-field> forventer.
fs brukes eventuelt på serveren eller i byggesteget. Datastar trenger den ikke i nettleseren.
HTML fra serveren
Section titled “HTML fra serveren”Datastar kan la serveren sende HTML underveis, over Server-Sent Events. Se @starfederation/datastar-sdk.
Et egendefinert element oppgraderer seg selv når det settes inn i dokumentet, så lenge defineFsField() har kjørt én gang. Serveren kan derfor sende dette som ren HTML:
<fs-field required-marker="text" invalid> <label>E-postadresse</label> <input class="fs-input" type="email" value="ola@" /> <p class="fs-help-text">Vi sender kvittering hit.</p> <p class="fs-error-text">Skriv en gyldig adresse.</p></fs-field>Komponenten kobler da for og id, setter fs-label, legger på aria-invalid og bygger aria-describedby, uten at det sendes JavaScript med for akkurat dette feltet.
Det er poenget med at ramme-komponentene bor i vanlig DOM: markupen er dataen, og tilgjengeligheten kobles der den lander.
Kjente fallgruver
Section titled “Kjente fallgruver”| Symptom | Årsak |
|---|---|
| Elementet vises ikke, siden ser tom ut | define-funksjonen har ikke kjørt |
customElements is not defined | Registreringen kjøres under serverrendering |
| Feltet er alltid ugyldig | invalid="false" er satt. Attributtet må fjernes, ikke settes til false |
SyntaxError i nettleseren | TypeScript-syntaks i en <script type="module"> uten byggesteg |
| Stilene mangler | tokens.css er ikke importert, eller importeres etter komponentens eget stilark |
React: «Invalid DOM property class» | Importer fs fra @fristil/designsystem/react |