One component library.
Every framework. Every browser.
UWC Components are built on the browser platform — native dialog, popover, and
popovertarget APIs under the hood — wrapped in Lit for a lean, reactive authoring experience
that drops into any stack.
Works everywhere you do
Write your component once. Use it in any framework — or none at all.
.prop and @event binding out of the box
[prop] binding and (event) listeners, signals-ready
:prop and @event — Vue's template syntax just works
<!-- Drop it in plain HTML — no build step required -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@uwc/components/+esm"></script>
<uwc-button variant="primary">Click me</uwc-button>
<uwc-dropdown placeholder="Select..."></uwc-dropdown>
Built on the browser platform
No polyfill soup. No virtual DOM. UWC Components reach directly for the primitives the browser already ships.
dialog
API
Modals and dialogs use the native <dialog> element — proper focus trapping, backdrop,
and ESC dismiss with zero JS overhead.
popover
API
Tooltips, dropdowns, and menus use the native Popover API — top-layer rendering, light-dismiss, and no z-index wars.
popovertarget
wiring
Trigger elements use popovertarget / popovertargetaction so panels open
without a single line of JavaScript.
CSS Anchor
positioning
Overlay placement is driven by CSS Anchor Positioning — no JS layout calculations, smooth browser-native repositioning.
One codebase. Every output.
The same uwc-* tag name works identically in every framework. There is no separate Angular
build, no separate React package, no adapter layer to maintain.
// Lit — property and event binding
html`<uwc-dropdown .options=${this.options} @uwc-change=${this.onChange}></uwc-dropdown>`
// Angular — same semantics
// <uwc-dropdown [options]="options" (uwc-change)="onChange($event)"></uwc-dropdown>
// Vue — same semantics
// <uwc-dropdown :options="options" @uwc-change="onChange"></uwc-dropdown>
// React 19 — direct JSX
// <uwc-dropdown options={options} onUwcChange={onChange} />