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

# Expose your UI components

> Share your components while keeping app code isolated.

Apps run in a sandbox, without direct access to your components or the surrounding page. A component schema describes what they can use: its props, events, and children.

Patchsmith generates stand-in components for the sandbox. A local bridge passes UI updates to your real components and sends events back to app code. Updates cross this bridge in the browser without a server round trip.

## Define a component

A button shows a component schema with behavior guidance:

```ts title="patchsmith.ts" theme={null}
import { defineContract } from "patchsmith";
import { z } from "zod";

export const contract = defineContract({
  components: {
    Button: {
      description:
        "Runs onClick when activated by pointer or keyboard. disabled blocks activation. Children provide the button label.",
      fields: z.object({
        variant: z.enum(["default", "secondary"]).optional(),
        disabled: z.boolean().optional(),
      }),
      callbacks: { onClick: {} },
      children: true,
    },
  },
});
```

| Part | What it does | Button example |
| - | - | - |
| `description` | Explains usage and behavior to app authors and agents | How activation and disabled state work |
| `fields` | Describes data props | `variant="secondary"`, `disabled` |
| `callbacks` | Describes events sent back to app code | `onClick` |
| `children` | Allows text or nested components inside | The button's label |

## Connect the real component

Map the schema's name to your existing button when you create the client:

```tsx title="patchsmith-client.tsx" theme={null}
import { Button } from "@/components/button";
import { createClient } from "patchsmith/react";
import { contract } from "./patchsmith";

export const patchsmith = createClient({
  contract,
  baseUrl: "http://localhost:3000/api/patchsmith/",
  components: {
    Button: ({ props, children }) => <Button {...props}>{children}</Button>,
  },
});
```

A callback describes an event on a component. For an action such as opening a toast or navigating, expose a [client tool](/docs/concepts/tools#client-tools) instead.

See [Write app UI](/docs/writing-apps/ui) for using these components in an app.

## Change a component schema

Removing a field, an allowed variant such as `"secondary"`, or a callback can break apps that use it. Adding a required field can break them too. Prefer optional additions and keep existing names and values until those apps have migrated.

## SDK reference

Each entry in `defineContract({ components })` describes one component. `Schema` means a Standard Schema validator, such as Zod.

| Field | Type | Meaning |
| - | - | - |
| `description` | `string` | Optional usage and behavior guidance, included in generated component references and binding comments. |
| `fields` | `Schema` | Data props. Field names must differ from callback names. |
| `callbacks` | Callback definitions by name | Function props for events such as `onClick`. |
| `children` | `boolean` | Defaults to `false`. Allows text or nested components inside. |

A callback can declare `input` for its event payload and `output` for its result. Its app implementation can return the result directly or return a promise. `{}` declares no arguments and a `void | Promise<void>` app return type.

Host callbacks always return promises because results cross the sandbox bridge. Await the result in your host component:

```ts theme={null}
const contract = defineContract({
  components: {
    Editor: {
      callbacks: { onValidate: { output: z.boolean() } },
    },
  },
});

// App implementation; returning Promise<boolean> is also accepted.
const onValidate = () => true;

// Host component:
const valid = await props.onValidate();
```

Callbacks cannot supply an immediate return value to a host API that requires a synchronous result. Callback exceptions and rejected promises reject the host promise. Pending calls reject when the sandbox closes or after 30 seconds without a result.

```ts theme={null}
export interface CallbackDefinition<
  TInput extends Schema | undefined = Schema | undefined,
  TOutput extends Schema | undefined = Schema | undefined,
> {
  input?: TInput;
  output?: TOutput;
}
```

## Frequently asked questions

Apps can use only the components you expose. Use tools for actions that do not describe component events.

<AccordionGroup>
  <Accordion title="Can an app import any component from my codebase?">
    It uses generated stand-ins for the components you expose in the contract.
    The client mapping keeps the real implementations outside the sandbox.
  </Accordion>

  <Accordion title="Should showing a toast be a component callback?">
    Use a [client tool](/docs/concepts/tools#client-tools) such as `showToast` for
    that action. Callbacks describe events from a rendered component, such as a
    click or selection.
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.