# 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.

```svelte title="basic.svelte"
<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>
```

Choose Grid, then reload the page. The files come back in the view you chose, and the console logs each change.

## Installation

```bash
npm install @ui-sdk/svelte @ui-sdk/core
```

## Usage

Define the preference you want to apply. Here, `view` chooses how a file list is laid out:

```ts title="preferences.ts"
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:

```svelte title="file-list.svelte"
<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>
```

```css
[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:

```ts title="preferences.ts"
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`](/docs/core/behaviors/preferences#remember-the-choice).

## Read the Value

Use `usePreference` when the value affects what your component renders:

```svelte title="view-switch.svelte"
<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:

```ts
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](/docs/core/behaviors/preferences#choose-a-color-scheme):

```svelte
<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](/docs/svelte/server-rendering#saved-preferences-and-storage) 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:

```svelte
<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](#usage).          |
| `nonce?`      | `string`                    | The nonce your Content Security Policy gives inline scripts. See [Server Rendering](#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.
