Preferences
Apply user preferences to data attributes so your styles can follow them.
Preferences puts your preferences on data-* attributes and keeps them up to date. Use it around a part of your app, or apply a preference to the whole page.
<script lang="ts">
import { createLocalStorage, createPreference } from "@ui-sdk/core"
import { Button } from "@ui-sdk/svelte/button"
import { Preferences, usePreference } from "@ui-sdk/svelte/preferences"
import { useLog } from "./log"
const view = createPreference({
values: ["list", "grid"],
defaultValue: "list",
attribute: "data-view",
storage: createLocalStorage("ui-sdk-preferences-view"),
})
const files = [
{ name: "Q3 roadmap.pdf", detail: "2.4 MB" },
{ name: "Launch checklist.md", detail: "12 KB" },
{ name: "Offsite photos", detail: "24 items" },
{ name: "Brand assets.zip", detail: "18 MB" },
]
const log = useLog()
const state = usePreference(view)
function choose(next: "list" | "grid", event: MouseEvent) {
view.set(next, { reason: "press", event })
log(`Saved the ${next} view`)
}
</script>
<Preferences preferences={[view]}>
<div data-slot="stack">
<div data-slot="controls" role="group" aria-label="View">
<Button
aria-pressed={state.current.value === "list"}
onclick={(event) => choose("list", event)}
>
List
</Button>
<Button
aria-pressed={state.current.value === "grid"}
onclick={(event) => choose("grid", event)}
>
Grid
</Button>
</div>
<ul data-slot="files" aria-label="Files">
{#each files as file (file.name)}
<li>
<span>{file.name}</span>
<span data-slot="hint">{file.detail}</span>
</li>
{/each}
</ul>
</div>
</Preferences>Installation
npm install @ui-sdk/svelte @ui-sdk/coreUsage
Define the preference you want to apply. Here, view chooses how a file list is laid out:
import { createPreference } from "@ui-sdk/core"
const view = createPreference({
values: ["list", "grid"],
defaultValue: "list",
attribute: "data-view",
})
export { view }Pass it to Preferences, then style the content by its attribute:
<script lang="ts">
import { Preferences } from "@ui-sdk/svelte/preferences"
import { view } from "./preferences"
</script>
<Preferences preferences={[view]}>
<ul data-slot="files">
<li>Q3 roadmap.pdf</li>
<li>Launch checklist.md</li>
</ul>
</Preferences>[data-view="grid"] [data-slot="files"] {
display: grid;
grid-template-columns: repeat(2, 1fr);
}Preferences starts with data-view="list". Calling view.set("grid") updates it, and the list becomes a grid. Preferences renders with display: contents, so it adds no box of its own.
Save the Value
Add storage to save the choice between visits:
import { createLocalStorage, createPreference } from "@ui-sdk/core"
const view = createPreference({
values: ["list", "grid"],
defaultValue: "list",
attribute: "data-view",
storage: createLocalStorage("ui-sdk-preferences-view"),
})
export { view }The preference now saves changes in local storage and restores the saved value when the page reloads. You can also use session storage or cookies with createPreference.
Read the Value
Use usePreference when the value affects what your component renders:
<script lang="ts">
import { usePreference } from "@ui-sdk/svelte/preferences"
import { view } from "./preferences"
const state = usePreference(view)
</script>
<button
aria-pressed={state.current.value === "grid"}
onclick={() => view.set(state.current.value === "grid" ? "list" : "grid")}
>
Grid
</button>Pass the same preference instance wherever you need its value. usePreference also works outside a Preferences component.
Apply to the Whole Page
Set global: true when defining the preference:
const view = createPreference({
values: ["list", "grid"],
defaultValue: "list",
attribute: "data-view",
global: true,
storage: createLocalStorage("ui-sdk-preferences-view"),
})Keep passing it to Preferences. Its attribute now goes on <html>, so styles throughout the page can use it. A global preference needs only one mounted Preferences component to apply it.
Multiple Preferences
Pass more than one preference in the list. For example, you can apply view alongside a color scheme:
<Preferences preferences={[view, colorScheme]}>
<App />
</Preferences>Each preference uses its own attribute and global option. Wrappers that share a preference instance follow the same value. For independent choices, use separate preference instances and different storage keys.
Server Rendering
On the server, Preferences includes a script that applies saved values before the page paints. CSS can use those attributes immediately. usePreference starts with the server's value and updates after hydration.
Follow the server rendering setup to place Preferences in your app and keep cookie-backed preferences separate for each request.
If your Content Security Policy requires a nonce, pass the nonce from your response:
<Preferences preferences={[view]} {nonce}>
<App />
</Preferences>API Reference
Preferences
| Prop | Type | Description |
|---|---|---|
preferences | readonly PreferenceLike[] | The preferences to apply, from createPreference or createColorScheme. See Usage. |
nonce? | string | The nonce your Content Security Policy gives inline scripts. See Server Rendering. |
usePreference
usePreference(preference) returns an object whose .current getter tracks the preference's state. For a preference created with createPreference, read state.current.value. For a color scheme, .current also includes system and resolved. Keep reading .current where you render it so Svelte follows changes.