# Compose with the toolkit

Applications import public Svelte components from `@dg/ui` and load `@dg/ui/styles.css` once in the root layout. The package exports Svelte source, CSS and assets directly; it has no separate build or category entry points.

## State and content

Use Svelte 5 runes for application state and derived values. Components receive ordinary callback props such as `onclick`, `onsend` and `onselect`. DOM callbacks receive their native event; conversation callbacks document when they receive a string. Do not use Svelte 4 event directives or assume a CustomEvent wrapper.

Content goes through `children` or named snippets. A supplied snippet replaces the corresponding text fallback; `Card.title` and `Button.icon` accept either text or a snippet. Only an explicitly bindable prop supports two-way state: currently `ChatComposer.value` and `Tabs.value`. A component reference from `bind:this` is available after mounting and exposes only documented instance methods.

```svelte
<script>
  import { Button, Card, Section } from "@dg/ui";
  let count = $state(0);
</script>

<Section>
  <Card title="Collection">
    {#snippet header()}<span>Archive</span>{/snippet}
    <p>Explore the collection and its documents.</p>
    {#snippet footer()}<span>{count} selections</span>{/snippet}
  </Card>
  <Button label="Select" icon="+" onclick={() => count++} />
</Section>
```

Every component forwards native attributes, DOM callbacks, `class` and `style` to its root element, except the names it owns itself; each reference's Notes name that root. Do not target a component's private markup with global selectors.

Forwarded attributes use the native types from `svelte/elements`, not an unrestricted property map. Use string class names, CSS text for style, native callbacks and appropriate `aria-*` or `data-*` attributes. A forwarded attribute does not add toolkit behavior: passing a loading attribute cannot implement a request lifecycle. `Button` and `Card` change their native root when href is supplied; choose attributes for that root. `Header`, `Footer` and `Tabs` do not render arbitrary children. `Heading` forwards `Section`'s padding and crosses but owns its children and fixes gap to 0.

Type checks catch misspelled props and invalid values in typed consumers; they do not validate every JavaScript spread, CSS expression, accessible name or semantic combination. Check the actual composition and its state transitions as well.

## Composition constraints

The [quick reference](quick-reference.md#compose-a-route) maps each need to its component or class, and its [rules](quick-reference.md#rules) apply everywhere. Composition adds these specific constraints:

- `Grid` and `Cards` keep jointive tracks: add no gap between their cells and never repair their lines with overlapping borders.
- `.formatted` already spaces its blocks; do not also wrap its paragraphs in a stack.
- A linked `Card` is one link: use an article `Card` when its content includes links or buttons. Never nest `ChatComposer`'s form in another form.
- Keep small screens free of horizontal page overflow: let text wrap, keep control targets and check long labels, empty content and large text.

## State contract

Implement states only where they apply. A static heading does not need loading, and a disabled action is not the same as a read-only value. Appearance uses the [interaction and feedback tokens](../foundations/interaction.md#interaction-states); semantics remain with the native element, component or application.

| State                          | Required behavior                                                                                                                                  | Owner                                                              |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Rest, hover and keyboard focus | Clear affordance, visible keyboard focus in either theme; hover is not the only route to information.                                              | Native element and shared component.                               |
| Disabled or unavailable        | Prevent activation and communicate why when needed. Native disabled controls leave the tab order; ARIA-disabled controls need an activation guard. | Component for documented disabled behavior; app for availability.  |
| Read-only                      | Keep the value readable, selectable and focusable; do not imply the control is unavailable.                                                        | Native field.                                                      |
| Pending                        | Prevent duplicate requests, announce progress, retain cancellation when useful, then restore an actionable state.                                  | App request lifecycle; `ChatComposer` exposes pending and stop.    |
| Invalid or failed              | Explain the problem in text and associate field errors; offer recovery without discarding useful input.                                            | App validation and requests.                                       |
| Empty or successful            | Distinguish no content, no results and a completed action; provide a next action where useful.                                                     | App content; shared components supply presentation.                |
| Open, closed or selected       | Keep ARIA state synchronized, define Escape and arrow-key behavior where applicable, and restore focus on dismissal.                               | Documented navigation, `Dialog`, `Tabs` and `ChatWindow` behavior. |

Reduced motion, forced colors, narrow layouts and both themes are verification conditions across these states, not additional business states. Use the [native field contract](../foundations/native-forms.md#native-fields-and-feedback) and [chat lifecycle](../guides/chat.md) for complete examples. Test state transitions, not just a static screenshot of each state.

## Ownership

The application owns domain data, routing, requests, sanitization, persistence and app-specific components; the toolkit supplies presentation and the documented interaction behavior. The [reference index](../README.md) is the complete public inventory.
