---
title: "API Reference"
description: "The complete public API of the GlassHome widget SDK. Every export across the main entry, /schemas, and /vite, with signatures."
canonical: https://glasshome.app/docs/widgets/widget-api-reference
section: "SDK"
updated: 2026-10-04
---
# API Reference

Every public export of `@glasshome/widget-sdk`, with signatures, by entry point. The [Widget SDK guide](/docs/widgets/widget-sdk) walks the important APIs with worked examples. Anything not listed here is internal and may change without notice.

## Entry points

| Import                                   | Use it for                                                                                            |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `@glasshome/widget-sdk`                  | Everything you use at runtime: `defineWidget`, components, hooks, the data layer, utilities, theming. |
| `@glasshome/widget-sdk/schemas`          | Zod schemas for validating manifests and publish payloads. Used by the CLI and Hub.                   |
| `@glasshome/widget-sdk/vite`             | Build plugins and helpers for `vite.config.ts`. The scaffold wires these for you.                     |
| `@glasshome/widget-sdk/tailwind-sources` | A CSS file the build feeds to Tailwind. Referenced by the scaffold; not imported in widget code.      |

Most types named below are exported too. SolidJS conventions apply: `Accessor<T>` is `() => T`, and an argument typed `Accessor<X> | X` accepts a plain value or an accessor.

> **Always import the data layer from the SDK:** Home Assistant hooks (`useEntity`, `useService`, …) are re-exported from the SDK on purpose. Importing them from @glasshome/sync-layer directly fails the build and would bundle a second, disconnected store. See Capabilities.

---

## `@glasshome/widget-sdk` (main entry)

### Core

```ts
function defineWidget<C = Record<string, unknown>>(
  definition: WidgetDefinition<C>
): WidgetDefinition<C>
```

Declares a widget. When `definition.configSchema` is present, it auto-populates `manifest.schema` (JSON Schema) and `manifest.defaultConfig`. See [the guide](/docs/widgets/widget-sdk#definewidget).

```ts
const SDK_VERSION: string  // the installed package version, e.g. "1.2.0"
```

The host compares `SDK_VERSION` against each widget's `manifest.sdkVersion` range.

### Components

`Widget` carries its slots as static members (`Widget.Icon`, `Widget.Title`, …); each is also exported standalone.

| Export                                   | Props (key)                                                                                                             | What it is                                                                                                                          |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `Widget`                                 | `variant`, `tone`, `color`, `colorTo`, `gradient`, `loading`, `emptyState`, `gestures`, `confirmed` (SDK 1.17), `class` | The container: shell, gestures, theming. See [Widget component](/docs/widgets/widget-sdk#widget-component).                         |
| `WidgetContent` / `Widget.Content`       | `children`, `accent?`, `class?`                                                                                         | Layout wrapper; with a `Widget.Head` inside, the tile layout (SDK 1.17).                                                            |
| `WidgetHead` / `Widget.Head`             | `name`, `icon?`, `eyebrow?`, `aside?`, `active?`, `count?`                                                              | Icon, small line, name, chips (SDK 1.17).                                                                                           |
| `WidgetHero` / `Widget.Hero`             | `value`, `unit?`, `sub?`, `art?`                                                                                        | The big reading and the tile's art (SDK 1.17).                                                                                      |
| `WidgetControls` / `Widget.Controls`     | `children`                                                                                                              | The control row (SDK 1.17).                                                                                                         |
| `WidgetStepper` / `Widget.Stepper`       | `label`, `onStep(-1 \| 1)`                                                                                              | Minus and plus (SDK 1.17).                                                                                                          |
| `WidgetChoice` / `Widget.Choice`         | `label`, `value`, `options`, `onChange`, `tone?`                                                                        | Icon options (SDK 1.17).                                                                                                            |
| `WidgetAction` / `Widget.Action`         | `icon`, `run`, `children?`, `aria-label?`, `confirm?`, `id?`                                                            | Ticks after an action that leaves no state (SDK 1.17).                                                                              |
| `WidgetChip` / `Widget.Chip`             | `children`, `icon?`, `tone?`                                                                                            | Small badge (SDK 1.17).                                                                                                             |
| `WidgetBackdrop` / `Widget.Backdrop`     | `children`                                                                                                              | Full-bleed picture under a scrim (SDK 1.17).                                                                                        |
| `WidgetLayer` / `Widget.Layer`           | `children`, `class?`                                                                                                    | Your own full-tile layer, edge to edge (SDK 1.17).                                                                                  |
| `WidgetGlyph` / `Widget.Glyph`           | `icon`                                                                                                                  | Faint corner icon (SDK 1.17).                                                                                                       |
| `WidgetIcon` / `Widget.Icon`             | `icon`, `color?`, `dimmed?`, `entityCount?`                                                                             | Entity icon tile with adaptive color.                                                                                               |
| `WidgetTitle` / `Widget.Title`           | `children`, `badge?` (number)                                                                                           | Primary label. `badge` renders a count pill when above 0.                                                                           |
| `WidgetStatus` / `Widget.Status`         | `children`, `dimmed?`, `isUnavailable?`                                                                                 | State text.                                                                                                                         |
| `WidgetValue` / `Widget.Value`           | `value` (number \| string), `unit?`, `interpret?`                                                                       | Numeric/formatted value. Takes no children: it formats `value` and appends `unit` itself, and renders `--` when `value` is missing. |
| `WidgetSliderFill` / `Widget.SliderFill` | `value` (0–100), `color?`, `isDragging?`                                                                                | Animated background fill for slider widgets.                                                                                        |
| `WidgetDialog`                           | see [WidgetDialog component](/docs/widgets/widget-sdk#widgetdialog-component)                                           | Settings/detail dialog. Renders no chrome of its own; inject UI via props.                                                          |

### Widget hooks

```ts
function useWidgetContext(): ReactiveWidgetContext
```

Reactive widget context. Must be called inside the `<Widget>` tree.

```ts
interface ReactiveWidgetContext {
  updateConfig: (config: Record<string, unknown>) => void;
  dimensions: () => { width: number; height: number };  // deprecated since 1.9.0, use useWidgetDimensions()
  registerDialogOpener?: (open: ((tab?: string) => void) | null) => void;
  callService?: ServiceCallFn;  // present when capability-routed by the host
}
```

`isEditMode` was removed in 1.9.0 (nothing read it; the host provided a constant `false`).

```ts
function useWidgetDashboard(): () => { name: string; icon: string; areaId: string | null }
```

The dashboard the widget is on. Updates live if someone renames it. Hosts that predate this field return empty values, so treat `name` and `icon` as possibly empty and `areaId` as possibly `null`.

```ts
function useMaterial(): () => { id: string; terms: MaterialTerms }
```

Which material the home has (Glass, Frosted, Paper, Neon, Chalk or one made in the creator studio), with every setting filled in. Updates when the home changes material. Use it for decisions, like leaving out a glow when `terms.glow` is 0; keep the colors in CSS with the [material variables](/docs/widgets/widget-sdk/materials). On a dashboard older than GlassHome 1.4.0-beta.11, it gives you Glass.

```ts
function useWidgetDimensions(): () => { width: number; height: number }
```

Measured shell size in CSS px. Call it in a component **inside** `<Widget>`; it throws anywhere else.

`ctx.dimensions()` is deprecated (removed in 2.0.0): outside `<Widget>` it silently read the host's stub, which returns `(0,0)` forever, locking a widget into its smallest layout. This hook throws instead.

```ts
function useConfirm(): { has(key: string): boolean; any(): boolean; run(keys: string[], action: () => unknown): Promise<boolean> }
```

Confirms actions that leave no state: `run` calls the action and marks `keys` for a moment when it succeeds, resolving whether it did. Share one with `Widget.Action` (`confirm`) and `<Widget confirmed={confirm.any()}>` (SDK 1.17).

```ts
function useWidgetEntityGroup<TData = unknown>(
  options: UseWidgetEntityGroupOptions<TData>
): UseWidgetEntityGroupResult<TData>
```

Aggregate one or many entities with presets + empty state. Options: reactive `entities: Accessor<EntityView[]>`, an `aggregationMode` (`"light" \| "sensor" \| "switch" \| "binary-sensor" \| "none"`) or a custom `calculateGroupData`, plus `emptyStateConfig`, `sensorGroupType`, `allEntitiesMode`, and `minEntities`. Returns `entities`, `groupData`, `aggregatedData`, `emptyState`, `hasEntities`, and `count` accessors. Full tables in [the guide](/docs/widgets/widget-sdk#usewidgetentitygroupoptions).

```ts
function useWidgetDialog(defaultTab = "controls"): WidgetDialogReturn
```

Open/close + active-tab state for `WidgetDialog`. Returns `showDialog`, `setShowDialog`, `openDialog`, `closeDialog`, `activeTab`, `setActiveTab`, and a `dialogProps` bag to spread onto `<WidgetDialog>`.

```ts
function useWidgetGestures(
  config: () => GestureConfig,
  orientation?: () => "horizontal" | "vertical" | "square"
): GestureHandlers
```

Tap, hold, and slide gestures for any pointer. `GestureConfig` = `{ tap?, hold?: { action, delay? }, slide?: { value, onChange, min?, max?, orientation?, activationDelay? } }`. Pass the returned `GestureHandlers` to `<Widget gestures={…} />`; call `.dispose()` in `onCleanup`.

```ts
function useReducedMotion(): Accessor<boolean>      // prefers-reduced-motion; false if unavailable (SSR-safe)
function useIntersectionPause(el: Accessor<Element | undefined>): Accessor<boolean>  // true while off-screen
```

| Export      | Kind            | What it is                                                               |
| ----------- | --------------- | ------------------------------------------------------------------------ |
| `WidgetCtx` | SolidJS context | The context object behind `useWidgetContext`. Advanced; prefer the hook. |

### Config schema helpers

Since 1.4.0 the config surface is `defineConfig` + `field.*` (see the [Config API](/docs/widgets/widget-sdk/config)):

```ts
function defineConfig<S>(shape: S): ConfigSchema<S>;
const field: {
  title(): Field<string | undefined>;
  text(o): Field<string>;
  number(o): Field<number>;
  toggle(o): Field<boolean>;
  choice<T>(values: readonly T[], o): Field<T>;
  entities(domain: string, o?): Field<string[]>;
  entity(domain: string, o?): Field<string[]>;
  area(o?): Field<string | undefined>;
  stringList(o): Field<string[]>;
  group<S>(shape: S, o): Field<Infer<S>>;
};
type Infer<C>;   // config type from a schema, without naming zod
```

`z` is re-exported from the SDK as a permanent escape hatch for schemas `field.*` can't express.

```ts
// Deprecated — use field.* / defineConfig (removed in a future major).
const widgetFields: {
  title(): ZodType;                                              // → field.title()
  entityIds(domain: string, opts?: { deviceClass?: string }): ZodType;     // → field.entities(domain, opts)
  singleEntity(domain: string, opts?: { deviceClass?: string }): ZodType;  // → field.entity(domain, opts)
  areaId(): ZodType;                                            // → field.area()
}
```

`widgetFields` and raw `z.object` config are deprecated. Run `bun widget migrate config`. See the [Config API](/docs/widgets/widget-sdk/config).

### Home Assistant data hooks

Reactive accessors over the host's live store. Each `entityId` arg accepts a string or an accessor. Declare every domain you read in your [capabilities](/docs/widgets/widget-capabilities): that declaration is what the user sees and approves when they install your widget.

| Export                | Signature                                                                                                  | What it is                                                                                                                                                                                                |
| --------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `useEntity`           | `(id: Accessor<string> \| string) => Accessor<EntityView \| undefined>`                                    | One entity by id.                                                                                                                                                                                         |
| `useEntities`         | `(ids: Accessor<string[]>) => Accessor<EntityView[]>`                                                      | Many entities from an id-array accessor.                                                                                                                                                                  |
| `useArea`             | `(id: Accessor<string> \| string) => Accessor<AreaView \| undefined>`                                      | An area and its entities.                                                                                                                                                                                 |
| `useEntityHistory`    | `(id) => Accessor<EntityHistoryData \| undefined>`                                                         | Recent state history.                                                                                                                                                                                     |
| `useEntityStatistics` | `(id, options) => Resource<StatisticValue[]>`                                                              | Long-term statistics; resource exposes `.loading` / `.error`.                                                                                                                                             |
| `useForecast`         | `(id) => Accessor<WeatherForecastsData \| undefined>`                                                      | Weather forecast for a weather entity.                                                                                                                                                                    |
| `useCamera`           | `(id) => { stream: Accessor<CameraStreamData \| null>; refresh: () => void }`                              | Reactive camera stream.                                                                                                                                                                                   |
| `useCalendarEvents`   | `(id, options?: { daysBehind?: number; daysAhead?: number }) => Accessor<CalendarEventsData \| undefined>` | Live events for a calendar entity, pushed by Home Assistant. Window defaults to 7 days behind and 35 ahead. Data carries `events`, `loading`, `error` and the subscribed `start`/`end`. Since SDK 1.10.0. |
| `useStore`            | `<T>(selector: (s) => T) => Accessor<T>`                                                                   | Direct store selector. Escape hatch.                                                                                                                                                                      |
| `byDomain`            | `Accessor<Record<string, string[]>>`                                                                       | All entity ids grouped by domain.                                                                                                                                                                         |

### Connection & locale hooks

| Export               | Signature                                   | What it is              |
| -------------------- | ------------------------------------------- | ----------------------- |
| `useConnection`      | `() => { status; isConnected }` (accessors) | Live connection status. |
| `useHassConfig`      | `() => Accessor<HassConfig \| null>`        | Home Assistant config.  |
| `useUnitSystem`      | `() => Accessor<HassUnitSystem \| null>`    | Unit system.            |
| `useTemperatureUnit` | `() => Accessor<string>`                    | e.g. `"°C"`.            |
| `useLocale`          | `() => Accessor<string>`                    | BCP 47 locale.          |
| `useCurrency`        | `() => Accessor<string>`                    | ISO 4217 currency.      |

### Services

```ts
function useService(): {
  callService: ServiceCallFn;
  turnOn:  (entityId: string | string[], data?: Record<string, unknown>) => Promise<void>;
  turnOff: (entityId: string | string[], data?: Record<string, unknown>) => Promise<void>;
  toggle:  (entityId: string | string[], data?: Record<string, unknown>) => Promise<void>;
}

type ServiceCallFn = (
  domain: string,
  service: string,
  data?: Record<string, unknown>,
  target?: { entity_id?: string | string[] },
  options?: { returnResponse?: boolean }
) => Promise<unknown>;
```

Host-mounted widgets route these through the host's capability check (a `control` grant is required); preview/tests fall back to direct sync-layer calls. `useTurnOn()`, `useTurnOff()`, and `useToggle()` each return just the one shortcut.

Pass `{ returnResponse: true }` for services that return data, such as `todo.get_items`; the promise then resolves to Home Assistant's service response instead of `undefined`. Only set it for services that support a response, since HA errors otherwise. The capability check is unchanged. Since SDK 1.10.0, and the host forwards the response from **Dash 1.1.0-beta.5** onward — on older hosts the call still runs but resolves `undefined`.

### Entity utilities

| Export                 | Signature                                                                                                      | What it is                                                                                           |
| ---------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `isEntityActive`       | `(entity: EntityView \| null \| undefined) => boolean`                                                         | `true` for active states.                                                                            |
| `getEntityAttribute`   | `<T>(entity, name: string, fallback?: T) => T \| undefined`                                                    | Read one attribute with a fallback.                                                                  |
| `hassMediaUrl`         | `(path: string \| null \| undefined) => string \| undefined`                                                   | Resolve an HA media path (album art, camera image) to a loadable URL. See [Media URLs](#media-urls). |
| `countActiveEntities`  | `(entities: EntityView[]) => number`                                                                           | Count active entities.                                                                               |
| `calculateLightGroup`  | `(entities: EntityView[], allEntitiesMode?= false) => LightGroupResult`                                        | Aggregate on/off, brightness, color across a group.                                                  |
| `calculateSensorGroup` | `(entities: EntityView[], groupType?: SensorGroupType = "mean", ignoreNonNumeric?= true) => SensorGroupResult` | Aggregate numeric sensors.                                                                           |

`LightGroupResult`: `isGroup`, `state`, `isOn`, `isUnavailable`, `brightness` (0–255), `brightnessPercent` (0–100), `color`, `onCount`, `totalCount`, `description`.
`SensorGroupResult`: `isGroup`, `state`, `numericValue` (`number \| null`), `isUnavailable`, `unit?`, `description`, `memberValues?`.
`SensorGroupType`: `"min" \| "max" \| "mean" \| "median" \| "sum" \| "last" \| "range" \| "product" \| "std_dev"`.

### Media URLs

Home Assistant exposes media references (album art `entity_picture`, camera proxy paths) as origin-relative paths like `/api/media_player_proxy/...?token=...`, which a bare `<img src>` resolves against the dashboard's own origin and fails to load. `hassMediaUrl` resolves them through the host's same-origin media proxy, so the image loads both **at home and over remote access** (no extra permissions, the path keeps Home Assistant's own signed token).

```tsx
import { hassMediaUrl, useEntity, getEntityAttribute } from "@glasshome/widget-sdk";

const entity = useEntity(entityId);

const albumArt = () => {
  const e = entity();
  if (!e) return undefined;
  return hassMediaUrl(getEntityAttribute<string>(e, "entity_picture"));
};

<Show when={albumArt()}>
  <img src={albumArt()} alt="" />
</Show>;
```

- Absolute `http(s)://` URLs pass through unchanged.
- Missing or empty input returns `undefined`, so `<Show when={albumArt()}>` handles "nothing playing" for free.
- No external service (cover-art API etc.) is needed for media Home Assistant already serves: read `entity_picture` and wrap it.
- Available since widget-sdk **1.3.0**.

`imageUrl` and `mediaUrl` do a different job: they resolve a household media-library id, which is what [`field.image()`](/docs/widgets/widget-sdk/config) stores, through the host's media store. Both are re-exported from `@glasshome/ui` since **1.12.0**.

### Theming & charts

| Export              | Signature                                      | What it is                                                                                                                                      |
| ------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `isDark`            | `() => boolean`                                | Current theme as a boolean.                                                                                                                     |
| `injectTokens`      | `(root?: Document \| ShadowRoot) => void`      | Attach SDK CSS tokens to a root the host did not set up.                                                                                        |
| `svgColors`         | `Record<SvgColorKey, { solid; stroke; fill }>` | Energy chart colors. Keys: `solar`, `grid`, `battery`, `ev`, `home`, `positive`, `negative`. See [Charts](/docs/widgets/widget-styling#charts). |
| `ToneSchema`        | Zod enum                                       | Validates a `Tone`.                                                                                                                             |
| `monotoneCubicPath` | `(points) => string`                           | Smooth SVG path string from a list of points.                                                                                                   |

`Tone`: `"success" \| "warning" \| "danger" \| "info" \| "neutral" \| "accent"`.

### Validation re-exports

Convenience re-exports also available from [`/schemas`](#glasshomewidget-sdkschemas).

| Export                 | Kind              | What it is                                |
| ---------------------- | ----------------- | ----------------------------------------- |
| `WidgetManifestSchema` | Zod schema        | Validate a complete widget manifest.      |
| `formatSchemaError`    | `(err) => string` | Turn a Zod error into a readable message. |

### Deprecation registry

The single source of truth for deprecated APIs, driving warn-once runtime notices, the CLI lint, and the deprecation docs table.

| Export              | Kind                                  | What it is                                              |
| ------------------- | ------------------------------------- | ------------------------------------------------------- |
| `deprecations`      | `DeprecationEntry[]`                  | The registry of deprecated APIs and their replacements. |
| `formatDeprecation` | `(entry: DeprecationEntry) => string` | Render one entry as a readable warning message.         |
| `DeprecationEntry`  | type                                  | One deprecation record.                                 |

### Lower-level data exports

Building blocks under the hooks; most widgets never touch these.

| Export                                        | Kind                    | What it is                                   |
| --------------------------------------------- | ----------------------- | -------------------------------------------- |
| `state`                                       | `Store<GlassHomeState>` | The raw reactive store.                      |
| `getForecasts`                                | function                | Imperative forecast fetch.                   |
| `trackEntityHistory` / `untrackEntityHistory` | `(entityId) => void`    | Start / stop history tracking for an entity. |
| `getStream`                                   | function                | Camera stream descriptor.                    |
| `getWebRtcClientConfig`                       | function                | WebRTC client config for camera streaming.   |
| `startWebRtcSession`                          | function                | Begin a WebRTC camera session.               |
| `sendWebRtcCandidate`                         | function                | Send an ICE candidate during a session.      |

### Types (main entry)

```ts
interface WidgetDefinition<C = Record<string, unknown>> {
  manifest: WidgetManifest;
  configSchema?: ZodType<C, unknown>;
  migrate?: (config: Record<string, unknown>, fromConfigVersion: number) => Record<string, unknown>;
  component: (props: { config: C }) => any;
}

interface WidgetManifest {
  name: string;
  description?: string;
  minSize: GridSize;          // { w, h }
  maxSize: GridSize;
  defaultSize?: GridSize;
  sdkVersion: string;
  icon?: string;
  capabilities?: CapabilityGrant[];
  configVersion?: number;
  schema?: object;            // auto-populated from configSchema; do not set
  defaultConfig?: Record<string, unknown>;  // auto-populated; do not set
  cssUrl?: string;            // set by the build
}

interface GridSize { w: number; h: number }
```

Other exported types: `WidgetContext`, `ReactiveWidgetContext`, `EntityView` (see [the shape](/docs/widgets/widget-sdk#the-entityview-shape)), `AreaView`, `WidgetVariantConfig`, `WidgetStyles`, `Tone`, `SvgColorKey`, `GestureHandlers`, `AggregationPreset`, `SensorGroupType`, `LightGroupResult`, `SensorGroupResult`, `UseWidgetEntityGroupOptions`, `UseWidgetEntityGroupResult`, `WidgetDialogProps`, `WidgetDialogTab`, `WidgetDialogReturn`, `ServiceCallFn`.

---

## `@glasshome/widget-sdk/schemas`

Zod schemas re-exported from the canonical `@glasshome/widget-contract` package, the single source of truth shared by the SDK, CLI, Hub, and Dash, so the same definitions validate a manifest everywhere.

| Export                                                                | Kind              | What it is                                         |
| --------------------------------------------------------------------- | ----------------- | -------------------------------------------------- |
| `widgetManifestSchema` (alias `WidgetManifestSchema`)                 | Zod schema        | Validate a complete widget manifest.               |
| `publishManifestSchema`                                               | Zod schema        | Validate the manifest subset sent at publish time. |
| `capabilitiesSchema`                                                  | Zod schema        | Validate a `capabilities` array.                   |
| `capabilityGrantSchema`                                               | Zod schema        | Validate one `{ domain, access }` grant.           |
| `GridSizeSchema`                                                      | Zod schema        | Validate `{ w, h }`.                               |
| `parseGridSize` / `serializeGridSize`                                 | functions         | Convert grid size to/from the stored JSON form.    |
| `PublishRequestSchema` / `PublishConfirmSchema` / `PublishBodySchema` | Zod schemas       | Publish-flow request bodies.                       |
| `formatSchemaError`                                                   | `(err) => string` | Turn a Zod error into a readable message.          |
| `CapabilityGrant`                                                     | type              | One capability grant.                              |

---

## `@glasshome/widget-sdk/vite`

Build plugins and helpers for `vite.config.ts`. The scaffolded config wires these; reach for them only in custom setups. See [Build tooling](/docs/widgets/widget-sdk#build-tooling).

| Export             | Signature                                          | What it is                                                      |
| ------------------ | -------------------------------------------------- | --------------------------------------------------------------- |
| `glasshomeWidget`  | `(options?: GlasshomeWidgetOptions) => Plugin[]`   | Single-widget plugin: dev preview + library build.              |
| `glasshomeWidgets` | `(options?: GlasshomeWidgetsOptions) => Plugin[]`  | Multi-widget plugin: per-widget builds + `registry.json`.       |
| `buildWidgets`     | `(options?: BuildWidgetsOptions) => Promise<void>` | Programmatic build of all widgets (used by `bun widget build`). |
| `discoverWidgets`  | `(srcDir: string) => DiscoveredWidget[]`           | Scan `src/` for subdirs with `index.tsx` + `manifest.json`.     |
| `generateRegistry` | `(srcDir: string, outDir: string) => void`         | Write a `registry.json` from discovered manifests.              |
| `isWidgetExternal` | `(id: string) => boolean`                          | `true` for host-provided packages (kept out of the bundle).     |

Option shapes (all exported):

- `GlasshomeWidgetsOptions`: `{ srcDir?, outDir? }` only.
- `BuildWidgetsOptions`: `{ srcDir?, outDir?, plugins?, viteConfig?, only? }` (`plugins`, `viteConfig`, and `only` are `buildWidgets`-only; `glasshomeWidgets` does not accept them).
- `GlasshomeWidgetOptions`: `{ entry? }` (defaults to `"src/index.tsx"`).

---

## UI primitives (re-exported from `@glasshome/ui`)

Import these from `@glasshome/widget-sdk`, not from `@glasshome/ui/solid`. The SDK re-export is the one `sdkVersion` gates; direct imports are deprecated since **1.9.0** and removed in **2.0.0**.

`WidgetDialog` takes its chrome as props and renders none of its own. Pass `ResponsiveDialog`, `ResponsiveDialogContent`, `ResponsiveDialogHeader`, `ResponsiveDialogTitle`, `ResponsiveDialogDescription` and `Button`; add `SchemaForm` when you use `configSchema`. See [WidgetDialog component](/docs/widgets/widget-sdk#widgetdialog-component).

Keep `@glasshome/ui` installed either way, since the build reads its styles.

The full re-export set, with the version each one arrived in, is in [Styling](/docs/widgets/widget-styling#importing-ui-components).