# Controllers

Read and change a component from outside its parts.

A controller connects code to a mounted component. Use one when the button or action that changes it lives somewhere else.

## Connect a Controller

Create it once in your component and pass it to the root:

```svelte
<script lang="ts">
  import { createToggleController, Toggle } from "@ui-sdk/svelte/toggle"

  const toggle = createToggleController()
</script>

<button onclick={() => toggle.toggle()}>Toggle Bold</button>
<Toggle controller={toggle}>Bold</Toggle>
```

Controller methods run the same change callbacks as user input. Controlled values and cancellation follow [State and Events](/docs/svelte/state-and-events).

Each component lists its methods, such as `open()`, `close()`, `setValue()`, or `focus()`.

A read like `toggle.isPressed()` answers when you call it, so call it from an event handler or async code. It returns `undefined` on the server and until the component is created, so markup that reads it renders differently on the server and the client. The markup doesn't update when the state changes either. To render the state, keep it in a variable with `bind:pressed`.

## Share a Popup

External triggers can use the same controller. A `payload` tells the content which item was opened:

```svelte
<script lang="ts">
  import {
    createPopoverController,
    Popover,
    PopoverContent,
    PopoverTitle,
    PopoverTrigger,
  } from "@ui-sdk/svelte/popover"

  const editor = createPopoverController<string>()
</script>

<PopoverTrigger controller={editor} payload="Notes">Edit Notes</PopoverTrigger>
<PopoverTrigger controller={editor} payload="Tasks">Edit Tasks</PopoverTrigger>
<Popover controller={editor}>
  <PopoverContent>
    {#snippet children(state)}
      <PopoverTitle>Edit {String(state.payload ?? "")}</PopoverTitle>
    {/snippet}
  </PopoverContent>
</Popover>
```

## Wait for a Popup to Close

A popup controller's `open()` returns a promise. It settles when the popup closes, with its reason and return value:

```ts
const result = await editor.open({ payload: "Notes" })
console.log(result.reason, result.returnValue)
```

For confirmations, [Alert Dialog](/docs/svelte/components/alert-dialog) provides `createConfirm()`, which gives you a function you can await.
