Skip to content

API Reference

Every public export of @glasshome/widget-sdk, with signatures, by entry point. This is the exhaustive reference; the Widget SDK guide walks the important APIs with worked examples. Anything not listed here is internal and may change without notice.

Entry points

ImportUse it for
@glasshome/widget-sdkEverything you use at runtime: defineWidget, components, hooks, the data layer, utilities, theming.
@glasshome/widget-sdk/schemasZod schemas for validating manifests and publish payloads. Used by the CLI and Hub.
@glasshome/widget-sdk/viteBuild plugins and helpers for vite.config.ts. The scaffold wires these for you.
@glasshome/widget-sdk/tailwind-sourcesA CSS file the build feeds to Tailwind. Referenced by the scaffold; not imported in widget code.

Most types named below are exported too, so you can annotate your own code. Reactive values follow SolidJS conventions: Accessor<T> is () => T, and any 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

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

Declares a widget. When definition.configSchema is present, defineWidget auto-populates manifest.schema (JSON Schema) and manifest.defaultConfig from it. See the guide.

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, …); the same components are also exported standalone.

ExportProps (key)What it is
Widgetvariant, tone, color, colorTo, gradient, loading, emptyState, gestures, classThe container: shell, gestures, theming. See Widget component.
WidgetContent / Widget.Contentchildren, class?Layout wrapper.
WidgetIcon / Widget.Iconicon, color?, dimmed?, entityCount?Entity icon tile with adaptive color.
WidgetTitle / Widget.TitlechildrenPrimary label.
WidgetStatus / Widget.StatuschildrenState text.
WidgetValue / Widget.ValuechildrenNumeric/formatted value.
WidgetSliderFill / Widget.SliderFillvalue (0–100), color?, isDragging?Animated background fill for slider widgets.
WidgetDialogsee WidgetDialog componentSettings/detail dialog. Renders no chrome of its own; inject UI via props.

Widget hooks

function useWidgetContext(): ReactiveWidgetContext

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

interface ReactiveWidgetContext {
  isEditMode: () => boolean;
  updateConfig: (config: Record<string, unknown>) => void;
  dimensions: () => { width: number; height: number };  // CSS px, (0,0) before first layout
  registerDialogOpener?: (open: ((tab?: string) => void) | null) => void;
  callService?: ServiceCallFn;  // present when capability-routed by the host
}
function useWidgetEntityGroup<TData = unknown>(
  options: UseWidgetEntityGroupOptions<TData>
): UseWidgetEntityGroupResult<TData>

Aggregate one or many entities with presets + empty state. Options take 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.

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>.

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.

function useReducedMotion(): Accessor<boolean>      // prefers-reduced-motion; false if unavailable (SSR-safe)
function useIntersectionPause(el: Accessor<Element | undefined>): Accessor<boolean>  // true while off-screen
ExportKindWhat it is
WidgetCtxSolidJS contextThe context object behind useWidgetContext. Advanced; prefer the hook.

Config schema helpers

const widgetFields: {
  title(): ZodType;                                              // text input "Title"
  entityIds(domain: string, opts?: { deviceClass?: string }): ZodType;     // multi-select entity picker
  singleEntity(domain: string, opts?: { deviceClass?: string }): ZodType;  // single-select entity picker
  areaId(): ZodType;                                            // area picker dropdown
}

Pre-built Zod fields with .meta() annotations the host’s form renderer reads. For anything else use Zod directly (z.boolean() → switch, z.enum() → dropdown). See widgetFields.

Home Assistant data hooks

Reactive accessors over the host’s live store. Each entityId arg accepts a string or an accessor. Reads are checked against your declared capabilities.

ExportSignatureWhat 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.
useStore<T>(selector: (s) => T) => Accessor<T>Direct store selector. Escape hatch.
byDomainAccessor<Record<string, string[]>>All entity ids grouped by domain.

Connection & locale hooks

ExportSignatureWhat 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

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[] }
) => Promise<void>;

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

Entity utilities

ExportSignatureWhat it is
isEntityActive(entity: EntityView | null | undefined) => booleantrue for active states.
getEntityAttribute<T>(entity, name: string, fallback?: T) => T | undefinedRead one attribute with a fallback.
countActiveEntities(entities: EntityView[]) => numberCount active entities.
calculateLightGroup(entities: EntityView[], allEntitiesMode?= false) => LightGroupResultAggregate on/off, brightness, color across a group.
calculateSensorGroup(entities: EntityView[], groupType?: SensorGroupType = "mean", ignoreNonNumeric?= true) => SensorGroupResultAggregate 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".

Theming & charts

ExportSignatureWhat it is
isDark() => booleanCurrent theme as a boolean.
injectTokens(root?: Document | ShadowRoot) => voidAttach SDK CSS tokens to a root the host did not set up.
svgColorsRecord<SvgColorKey, { solid; stroke; fill }>Energy chart colors. Keys: solar, grid, battery, ev, home, positive, negative. See Charts.
ToneSchemaZod enumValidates a Tone.
monotoneCubicPath(points) => stringSmooth 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.

ExportKindWhat it is
WidgetManifestSchemaZod schemaValidate a complete widget manifest.
formatSchemaError(err) => stringTurn a Zod error into a readable message.

Lower-level data exports

Advanced building blocks the hooks are built on. Most widgets never touch these.

ExportKindWhat it is
stateStore<GlassHomeState>The raw reactive store.
getForecastsfunctionImperative forecast fetch.
trackEntityHistory / untrackEntityHistory(entityId) => voidStart / stop history tracking for an entity.
getStreamfunctionCamera stream descriptor.
getWebRtcClientConfigfunctionWebRTC client config for camera streaming.
startWebRtcSessionfunctionBegin a WebRTC camera session.
sendWebRtcCandidatefunctionSend an ICE candidate during a session.

Types (main entry)

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), 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, the CLI, the Hub, and Dash), so the same definitions validate a manifest everywhere.

ExportKindWhat it is
widgetManifestSchema (alias WidgetManifestSchema)Zod schemaValidate a complete widget manifest.
publishManifestSchemaZod schemaValidate the manifest subset sent at publish time.
capabilitiesSchemaZod schemaValidate a capabilities array.
capabilityGrantSchemaZod schemaValidate one { domain, access } grant.
GridSizeSchemaZod schemaValidate { w, h }.
parseGridSize / serializeGridSizefunctionsConvert grid size to/from the stored JSON form.
PublishRequestSchema / PublishConfirmSchema / PublishBodySchemaZod schemasPublish-flow request bodies.
formatSchemaError(err) => stringTurn a Zod error into a readable message.
CapabilityGranttypeOne capability grant.

@glasshome/widget-sdk/vite

Build plugins and helpers for vite.config.ts. The scaffolded config wires these automatically; reach for them only for custom setups. See Build tooling.

ExportSignatureWhat 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) => voidWrite a registry.json from discovered manifests.
isWidgetExternal(id: string) => booleantrue for host-provided packages (kept out of the bundle).

BuildWidgetsOptions / GlasshomeWidgetsOptions: { srcDir?, outDir?, plugins?, viteConfig?, only? }. GlasshomeWidgetOptions: { entry?, … }. All three types are exported.


Dialog UI components (from @glasshome/ui)

WidgetDialog takes its chrome as props. These are not SDK exports; import them from @glasshome/ui/solid and pass them in (keep @glasshome/ui as a dependency). See WidgetDialog component.

ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogHeader, ResponsiveDialogTitle, ResponsiveDialogDescription, Button, SchemaForm (SchemaForm is required only when you use configSchema).