---
title: "Bits UI"
description: "Use Bits UI primitives to draw GistUI components in Svelte 5, with form validation and bind:$var still working."
---

> Documentation Index
> Fetch the complete documentation index at: https://gistui.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Bits UI

For Svelte 5 apps that use [Bits UI](https://bits-ui.com) primitives directly. If you use shadcn-svelte, which is built on Bits UI, start with [shadcn-svelte](/docs/ui-libraries/shadcn-svelte/).

```sh
npm i @gistui/svelte @gistui/styles @gistui/catalog bits-ui
yarn add @gistui/svelte @gistui/styles @gistui/catalog bits-ui
pnpm add @gistui/svelte @gistui/styles @gistui/catalog bits-ui
bun add @gistui/svelte @gistui/styles @gistui/catalog bits-ui
```

## A switch

Bits UI form primitives render a hidden native input when given `name`, so the GistUI Form around them can read the value.

```svelte title="GistSwitch.svelte"
<script lang="ts">
  import { Switch } from "bits-ui";
  import { gistField, type GistUIComponentProps } from "@gistui/svelte";

  let p: GistUIComponentProps = $props();
  const id = $props.id();
  const field = gistField(() => p.ctx, "bool"); // one on/off value
</script>

<div class="switch-row">
  <Switch.Root
    {id}
    name={field.current.name}
    disabled={field.current.locked}
    checked={field.current.bound ? field.current.value === true : p.props.checked === true}
    onCheckedChange={(on) => field.current.bound && field.current.setValue(on)}
    class="switch"
  >
    <Switch.Thumb class="switch-thumb" />
  </Switch.Root>
  <label for={id}>{field.current.label}</label>
</div>
```

## A card

```svelte title="GistCard.svelte"
<script lang="ts">
  import { GistChildren, type GistUIComponentProps } from "@gistui/svelte";
  let {}: GistUIComponentProps = $props();
</script>

<section class="my-card" data-gistui="Card"><GistChildren /></section>
```

## Register them

```svelte
<script lang="ts">
  import { GistUI } from "@gistui/svelte";
  import GistCard from "./GistCard.svelte";
  import GistSwitch from "./GistSwitch.svelte";
</script>

<GistUI source={answer} streaming={loading} components={{ Switch: GistSwitch, Card: GistCard }} onaction={onAction} />
```

## Notes

- Call `gistField` while the component initialises, and read it through `field.current`.
- Keep GistUI's built-in `Button` and style it with [tokens](/docs/guides/theming/): actions, form submits and dialogs then keep working.
- Bits UI ships no styles. Use tokens so the GistUI components you did not replace match yours.

Source: https://gistui.com/docs/ui-libraries/bits-ui/index.mdx
