Skip to content

Expose host UI primitives (Select, Segmented, Button, Popover) to custom widgets via @onno/widget-sdk #243

Description

@mikedegeofroy

Version: su.onno:onno-ui-starter:1.4.5

Problem

The widget SDK (@onno/widget-sdk) exposes the host's React, hooks, api, and html on window.onno — but not the host's UI component library (components/ui/*: Select, Segmented, Button, Popover, Badge, Checkbox, Switch, …).

So a custom widget that needs a dropdown, a view switcher, or a button has to re-implement those as lookalikes. Two problems with that:

  1. Inconsistency / drift. A hand-rolled <select> or a div-based menu won't match the real Radix-backed Select (facet drawer on mobile via vaul, keyboard nav, theming, animations). It diverges the moment the design system changes.
  2. The Tailwind-emission gotcha compounds it. Widget .tsx is compiled outside the host Tailwind build, so utility classes the host doesn't itself emit (opacity variants, size-*, arbitrary values) silently produce no CSS. To style a lookalike I had to inject a fallback <style> for exactly those utilities. Reusing the real components would sidestep this entirely.

Repro / context

Building a full-screen resource-scheduler widget (rooms × time grid, drag-to-move, filters, day/week/month switcher) on 1.4.5. To make the filter dropdowns and the view switcher match the rest of the app I copied onno's own class strings out of segmented.tsx / button.tsx / select.tsx and rebuilt the components by hand — because the real ones aren't importable from a widget.

Request

Expose the host UI primitives to widgets, e.g. one of:

  • add them to the window.onno host object and re-export from the SDK:
    import { ui } from "@onno/widget-sdk";
    const { Select, SelectTrigger, SelectContent, SelectItem, Segmented, Button, Popover, Badge } = ui;
  • or a dedicated entry @onno/widget-sdk/ui that the Gradle plugin aliases to the host bundle (same mechanism React is aliased today).

Since the plugin already aliases react/react/jsx-runtime to the host singletons, aliasing @/components/ui/* (or a curated subset) to the host should be a small extension of the existing esbuild alias config. A curated, documented subset (Select, Segmented, Button, Popover, Badge, Checkbox, Switch, Input) would cover the vast majority of widget needs.

Why it matters

Custom widgets are the sanctioned way to build surfaces the framework has no built-in for (calendars, schedulers, kanban, dashboards). Right now every one of them reinvents the control layer and risks visual drift from the product. Exposing the primitives makes widgets first-class citizens of the design system.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions