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
| 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, 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.
| Export | Props (key) | What it is |
|---|---|---|
Widget | variant, tone, color, colorTo, gradient, loading, emptyState, gestures, class | The container: shell, gestures, theming. See Widget component. |
WidgetContent / Widget.Content | children, class? | Layout wrapper. |
WidgetIcon / Widget.Icon | icon, color?, dimmed?, entityCount? | Entity icon tile with adaptive color. |
WidgetTitle / Widget.Title | children | Primary label. |
WidgetStatus / Widget.Status | children | State text. |
WidgetValue / Widget.Value | children | Numeric/formatted value. |
WidgetSliderFill / Widget.SliderFill | value (0–100), color?, isDragging? | Animated background fill for slider widgets. |
WidgetDialog | see WidgetDialog component | Settings/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
| Export | Kind | What it is |
|---|---|---|
WidgetCtx | SolidJS context | The 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.
| 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. |
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
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
| 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. |
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".
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. |
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.
| Export | Kind | What it is |
|---|---|---|
WidgetManifestSchema | Zod schema | Validate a complete widget manifest. |
formatSchemaError | (err) => string | Turn a Zod error into a readable message. |
Lower-level data exports
Advanced building blocks the hooks are built on. 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)
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.
| 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 automatically; reach for them only for custom setups. See 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). |
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).