# 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:

| Bundle | Components covered |
| --- | --- |
| `cdn/basic.js` | Basic: button, icon, tag, badge, space, divider, link, typography, button-group, label, kbd, visually-hidden |
| `cdn/layout.js` | Layout: layout, sidebar, container, grid, flex, splitter, scroll-area, masonry, aspect-ratio |
| `cdn/form.js` | Form: 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.js` | Feedback & 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.js` | Navigation: 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.js` | Data 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.js` | Conversation: bubble, attachment, message-scroller, marker, message-row |
| `cdn/workbench.js` | Workbench: titlebar, statusbar, inspector, action-bar |
| `cdn/framework.js` | Framework 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):

| Component | Capability (shipped with the main entry) | Capability subpath (for `/core`) |
| --------- | ---------------------------------------- | -------------------------------- |
| `oas-table` | Inline editing (`editable` / `editor` / `actions`) | `@oas-ui/ui/data/table/edit` |
| `oas-tabs` | Double-click rename / context menu / drag-sort (`editable` / `context-menu` / `sortable`) | `@oas-ui/ui/navigation/tabs/manager` |
| `oas-modal` | Prompt dialog (`modal.prompt()`) | `@oas-ui/ui/feedback/modal/prompt` |
| `oas-popover` | Cursor-anchored context menu / touch long-press / `placement`·`size` breakpoint shorthands | `@oas-ui/ui/feedback/popover/contextmenu` |
| `oas-color-picker` | 2D 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](https://github.com/openappsys/oas-ui/tree/main/packages/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](./theming) 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](./ssr): 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](./faq).
