Skip to content

Getting Started ​

CDN usage ​

Full bundle (simplest, registers all components): cdn.js is a pre-bundled IIFE file; just load it via a <script> tag:

html
<link rel="stylesheet" href="https://unpkg.com/@oas-ui/theme@2/index.css" />
<script src="https://unpkg.com/@oas-ui/ui@2/dist/cdn.js"></script>
<oas-button type="primary">Hello OAS-UI</oas-button>

Per-family bundles (a middle ground between size and coverage): components are grouped into 9 feature families. Each family ships as its own IIFE file and inlines the base (runtime plus config-provider/app/theme-editor), so no extra script is required:

BundleComponents covered
cdn/basic.jsBasic: button, icon, tag, badge, space, divider, link, typography, button-group, label, kbd, visually-hidden
cdn/layout.jsLayout: layout, sidebar, container, grid, flex, splitter, scroll-area, masonry, aspect-ratio
cdn/form.jsForm: input, textarea, checkbox, radio, switch, segmented, slider, input-number, rate, select, auto-complete, combobox, cascader, tree-select, mentions, date-picker, time-picker, calendar, upload, transfer, color-picker, toggle-button, toggle-group, pin-input, dynamic-input, dynamic-tags, editable, form, etc.
cdn/feedback.jsFeedback & Overlays: tooltip, popover, hover-card, message, notification, toast, snackbar, backdrop, modal, confirm, drawer, popconfirm, alert, progress, loading-bar, spin, skeleton, empty, result, bottom-sheet, notice-bar, pull-refresh
cdn/navigation.jsNavigation: menu, dropdown, contextmenu, command, menubar, navigation-menu, toolbar, breadcrumb, anchor, back-top, tour, tabs, bottom-navigation, pagination, steps, stepper, affix, page-header, float-button, speed-dial, app-bar, index-bar
cdn/data.jsData display: table, tree, virtual-list, card, avatar, avatar-group, image, qrcode, watermark, collapse, descriptions, timeline, list, carousel, statistic, countdown, ellipsis, chart, code, equation, log, marquee, number-animation, gradient-text, comment, etc.
cdn/conversation.jsConversation: bubble, attachment, message-scroller, marker, message-row
cdn/workbench.jsWorkbench: titlebar, statusbar, inspector, action-bar
cdn/framework.jsFramework containers: config-provider, app, theme-editor

Basic family only:

html
<link rel="stylesheet" href="https://unpkg.com/@oas-ui/theme@2/index.css" />
<script src="https://unpkg.com/@oas-ui/ui@2/dist/cdn/basic.js"></script>
<oas-button type="primary">Hello OAS-UI</oas-button>

Add a feedback family (a page that combines forms and message toasts):

html
<link rel="stylesheet" href="https://unpkg.com/@oas-ui/theme@2/index.css" />
<script src="https://unpkg.com/@oas-ui/ui@2/dist/cdn/basic.js"></script>
<script src="https://unpkg.com/@oas-ui/ui@2/dist/cdn/form.js"></script>
<script src="https://unpkg.com/@oas-ui/ui@2/dist/cdn/feedback.js"></script>

Choosing a rule: load per-family bundles when the components you need span ≤ 2 families (smaller than the full bundle); when they span ≥ 3 families, load the single full cdn.js instead — every family inlines the base, so stacking multiple families costs more duplicated base code than the all-in-one file.

Import a single component on demand: use the esm.sh short path (resolves dependencies automatically), which registers only that one component:

html
<script type="module">
  import 'https://esm.sh/@oas-ui/ui@2/basic/button'
</script>
<oas-button type="primary">Hello OAS-UI</oas-button>

For multiple components, add one short path each — only the components you use and their dependency chains are downloaded (e.g. the button chain is ≈ 27KB gzip, including the core runtime; on-demand mode does not include the full icon set — using built-in icon names needs import '@oas-ui/icons/register', see above); unused components cost nothing:

html
<script type="module">
  import 'https://esm.sh/@oas-ui/ui@2/basic/button'
  import 'https://esm.sh/@oas-ui/ui@2/basic/tag'
</script>

CDN entry-point note: the oas-*.js files under each component directory are pure class definitions (for bundler tree-shaking) and do not register anything; customElements.define runs in index.js. For direct CDN usage, use the full cdn.js above or the on-demand short path (resolved to index.js via the exports map). Do not import dist/basic/button/oas-button.js directly — the import succeeds but the element never registers, so nothing renders.

Install (npm / pnpm / yarn) ​

bash
pnpm add @oas-ui/ui @oas-ui/theme

Import ​

Full import (auto-registers all components):

ts
import '@oas-ui/theme'
import '@oas-ui/ui'

Import a single component on demand:

ts
import '@oas-ui/theme'
import '@oas-ui/ui/basic/button'

On-demand mode does not include the full built-in icon set (so each component chain doesn't carry every icon). If you use a built-in icon name (e.g. <oas-button icon="check">, <oas-icon name="close">), add import '@oas-ui/icons/register' once (the full entry @oas-ui/ui already includes it). Not needed if you only supply icons via registerIcon / registerIconLibrary / iconfont / slot.

Use directly in React / Vue (rendering, attributes and slot content work in both; event listening — see the section below):

tsx
// React: event listening — see "React event listening" below (native onoas-* lowercase works)
<oas-button type="primary" ref={btnRef}>Button</oas-button>
vue
<!-- Vue: @oas-click listens to the custom event directly -->
<oas-button type="primary" @oas-click="onClick">Button</oas-button>

Rendering and attribute passing need no wrappers in any of the three environments (React / Vue / vanilla). Events are dispatched as oas-* CustomEvents — Vue can listen via @oas-click directly; React 19 works with the native onoas-* lowercase form, while the camelCase convention needs the optional bridge (below).

React event listening ​

React 19 listens natively: only the "on + lowercase literal" form works — <oas-button onoas-submit={...}> does catch oas-submit; the idiomatic camelCase form <oas-button onOasSubmit={...}> silently fails (the prop is never mapped to an oas-submit listener on custom elements), lowercase dashed prop names are hostile to TS/JSX typing, and React 17/18 is not supported either.

tsx
// React 19: native form, no extra dependency
<oas-button type="primary" onoas-submit={(e) => console.log(e.detail.value)}>
  Submit
</oas-button>

Optional utility @oas-ui/react (in-repo, not released separately): when you need camelCase convention, type safety, or React 17/18 support, use the hooks — source lives in packages/react (reference it inside the monorepo); it is not published to npm.

tsx
import { useRef } from 'react'
import { useOasEvents } from '@oas-ui/react'

function Demo() {
  const btnRef = useRef<HTMLElement | null>(null)
  useOasEvents(btnRef, {
    'oas-submit': (detail) => console.log('submit', detail.value),
    'oas-cancel': () => console.log('cancel'),
  })
  return (
    <oas-button type="primary" ref={btnRef}>
      Submit
    </oas-button>
  )
}

For a single event use useOasEvent<Detail>(ref, 'oas-submit', handler). Both hooks always run the latest closure after re-renders and unbind automatically on unmount; event names must carry the oas- prefix. Full details live in packages/react/README.md.

Capability sub-packages (heavy capabilities ship with the main entry): a few components split heavy optional capabilities into standalone sub-packages that are bundled into the component's main entry — importing @oas-ui/ui/<group>/<component> from any main path includes every capability by default (import registers it; no extra import needed):

ComponentCapability (shipped with the main entry)Capability subpath (for /core)
oas-tableInline editing (editable / editor / actions)@oas-ui/ui/data/table/edit
oas-tabsDouble-click rename / context menu / drag-sort (editable / context-menu / sortable)@oas-ui/ui/navigation/tabs/manager
oas-modalPrompt dialog (modal.prompt())@oas-ui/ui/feedback/modal/prompt
oas-popoverCursor-anchored context menu / touch long-press / placement·size breakpoint shorthands@oas-ui/ui/feedback/popover/contextmenu
oas-color-picker2D color field / gradient designer (mode="gradient")@oas-ui/ui/form/color-picker/designer
ts
import '@oas-ui/ui/data/table' // the main entry already includes inline editing

If you prefer a lean core, import the new /core path of these components instead (e.g. @oas-ui/ui/data/table/core) — it omits the capabilities above, so the related options silently no-op with a dev-mode warning once; add the capability sub-path explicitly (import registers it) or switch back to the main entry when you need them:

ts
import '@oas-ui/ui/data/table/core' // pure core: no inline editing
import '@oas-ui/ui/data/table/edit' // explicit capability import (core path only)

Import order does not matter: capabilities registered later are retroactively applied to already-mounted elements. The full entry @oas-ui/ui and the CDN family bundles already include every capability — no extra imports needed there.

Want to see it live? The repo ships a Playground for React / Vue — run pnpm dev:react / pnpm dev:vue inside packages/playground (or pnpm --filter @oas-ui/playground dev:react from the repo root).

Browser support ​

Modern evergreen browsers: latest two major versions of Chrome / Edge / Firefox / Safari. Specifically:

  • Chrome / Edge (Chromium): full e2e coverage
  • Firefox: verified by real-browser testing (Firefox-specific pseudo-elements such as the slider track are adapted)
  • Safari ≥ 16.4: verified on the WebKit engine; Declarative Shadow DOM requires 16.4+, solid-state coloring (color-mix) requires 16.2+

Theme switching ​

html
<html data-theme="dark">
  <!-- switches to dark theme -->
</html>

Three built-in themes: light / dark / high-contrast. See the Theming guide for customization.

Your own CSS does not follow the theme automatically: variables inside components switch with data-theme, but styles you write yourself must reference var(--oas-color-*) to follow along. The most common pitfall is a page body without an explicit background — after switching to dark, components turn dark while the page stays at the browser default white:

css
body {
  background: var(--oas-color-bg);
  color: var(--oas-color-text-primary);
}

Event conventions (important) ​

All component events carry the oas- prefix: oas-change, oas-select, oas-input, oas-close, etc. (each component's API table lists the full set and when they fire). This is deliberate — Web Components events bubble to window by default, and unprefixed change/select would collide with native events and host-framework synthetic events; the prefix makes the origin unambiguous.

ts
// correct: oas- prefix
menu.addEventListener('oas-select', (e) => console.log(e.detail))

// wrong: never fires (a common first pitfall)
menu.addEventListener('select', (e) => console.log(e.detail))

Controlled components (switch / radio-group / checkbox-group / slider / input-number, etc.) write the latest value back to the host attribute after user interaction (e.g. value / checked), so el.getAttribute('value') reads the current state directly, consistent with the oas-change event's detail.value.

SSR ​

For server-side rendering, refer to the SSR strategy: side-effect imports of the component library should only run on the client.

For more integration questions (the ::part() customization trap, event timing, etc.), see the FAQ.

Released under the MIT OR Apache-2.0 License.