---
name: use-swim-ui
description: Use Swimlane swim-ui (swim-* custom elements) when building custom solutions, record widgets, or report widgets for Turbine. Covers properties, events, slots, imperative APIs, and CDN usage. Apply this skill when using generate-swimlane-lit-solution (it depends on use-swim-ui for component list, API, and design). Use when authoring or modifying Turbine widgets, custom solutions, or any UI that uses @swimlane/swim-ui components.
---

# Using Swimlane swim-ui

Use this skill when building **custom solutions** or **widgets** for [Swimlane Turbine](https://docs.swimlane.com/widgets) with **Swimlane swim-ui** (`swim-*` web components). All UI must use these elements; do not invent tag names or assume other component libraries.

## Base and runtime

- **Custom elements**: Extend **SwimlaneElement** (from `@swimlane/swimlane-element@2`), not raw LitElement. Use `css`, `html`, `svg`, `unsafeCSS` from that package.
- **Widget docs**: [Turbine Widgets](https://docs.swimlane.com/widgets) — record widgets and report widgets; implementations are web components / custom elements.
- **Component source**: Full APIs (properties, events, slots) live in `projects/swimlane/swim-ui/src/components/<name>/`. For precise attribute names and event payloads, read the component `.component.ts` and `index.ts` files.

## CDN usage (solutions without build)

```js
import { SwimlaneElement, css, html } from '@swimlane/swimlane-element@2';  // or https://esm.sh/@swimlane/swimlane-element@2
import 'https://cdn.jsdelivr.net/gh/surya-pabbineedi/swim-ui@gh-pages/swim-ui.js?v=1';
```

Ensure the `lit` specifier is available (e.g. via import map) so the swim-ui bundle resolves. Load SwimlaneElement (or Lit) before the swim-ui bundle.

## Attribute naming

- Lit properties are exposed as **kebab-case attributes**: `sectionCollapsed` → `section-collapsed`, `closeOnOutsideClick` → `close-on-outside-click`, `fontIcon` → `font-icon`.
- Booleans: presence = true; use `attribute="false"` or `close-on-outside-click="false"` where the component uses a custom converter for false.

## Events

### Host-only custom events (confirmed contract)

Swim-ui **custom events** are dispatched **only on the `swim-*` element host** (the custom element node: `event.target` is that element). They use **`bubbles: false`** and **`composed: false`**, so they **do not** propagate to ancestors, `document`, or past shadow boundaries.

**How to listen**

- **Lit:** use `@event` on the `swim-*` node that emits it (for example `@change` on `swim-input`, `@close` on `swim-dialog`), not on a wrapping `div` expecting the event to bubble up.
- **Vanilla:** `element.addEventListener('change', ...)` where `element` is the `swim-*` reference from `querySelector`, `ref`, or `createElement`.

**Do not** rely on **event delegation** on a parent, `document`, or `window` for these custom events—they will not fire there. (Native `click` on `swim-button` is separate: it behaves like a normal control.)

**Naming:** Because custom events stay on the host, conventional names (`change`, `close`, `open`, `select`, etc.) are safe. If a future API ever required **`bubbles: true`**, prefer a **non-generic, swim-specific** event name to avoid clashes.

Use `event.detail` for payloads where the component defines it.

### Propagation summary (`bubbles` / `composed`)

| | Value | Meaning |
|--|-------|--------|
| Custom events | `bubbles: false`, `composed: false` | Host-only; listen on that `swim-*` element. |

**Repro:** The swim-ui demo **Event propagation** (`#event-bubbling-matrix`) shows `swim-checkbox` in light DOM vs inside another shadow root.

### Per-event reference

| Element | Event | Bubbles | Composed | Detail |
|---------|-------|---------|----------|--------|
| swim-button | `click` | native | native | — |
| swim-input | `input`, `change`, `focus`, `blur` | no | no | value / validation |
| swim-select | `change`, `filter-change` | no | no | value / `{ query }` |
| swim-select | `dropdown-open`, `dropdown-close` | no | no | panel open state |
| swim-checkbox | `change`, `checked-change`, `indeterminate-change`, `focus`, `blur` | no | no | checked / indeterminate |
| swim-toggle | `change`, `focus`, `blur` | no | no | checked |
| swim-radio | `change`, `focus`, `blur` | no | no | value |
| swim-radio-group | `change`, `blur` | no | no | selected value |
| swim-button-toggle | `value-change` | no | no | value |
| swim-button-toggle-group | `value-change` | no | no | selected value |
| swim-slider | `change` | no | no | `{ value, percent }` |
| swim-calendar | `change`, `day-key-enter` | no | no | value / keyboard |
| swim-date-time | `change`, `value-change`, `input-change`, `date-time-selected`, `focus`, `blur` | no | no | value / segments |
| swim-tabs | `select-tab`, `select` | no | no | `{ tab }` |
| swim-tab | `swim-tab-active-change` | no | no | — |
| swim-section | `toggle` | no | no | collapsed boolean |
| swim-dialog | `open`, `close` | no | no | optional detail on close |
| swim-large-format-dialog-content | `close-or-cancel` | no | no | dirty boolean |
| swim-drawer | `close` | no | no | optional detail |
| swim-list | `page-change`, `scroll` | no | no | page / scrollTop |
| swim-card | `select`, `outline-click` | no | no | selected / — |
| swim-tooltip | `show`, `hide` | no | no | `true` |
| swim-navbar, swim-navbar-item | `active-change` | no | no | index |
| swim-split-handle | `dragstart`, `drag`, `dragend`, `dblclick` | no | no | `MouseEvent` detail |

## Slots

Common patterns:

- **Default slot**: main content (e.g. `swim-card`, `swim-dialog`, `swim-drawer`, `swim-tab` body).
- **Named slots**: `slot="header"`, `slot="footer"`, `slot="hint"`, `slot="prefix"`, `slot="suffix"`, `slot="content"` (tooltip), `slot="label"` (tab), `slot="avatar"`, `slot="title"`, `slot="subtitle"`.

Use the component’s JSDoc `@slot` in `projects/swimlane/swim-ui/src/components/<name>/*.component.ts` for the exact list.

## Imperative APIs

### Drawer

- **Declarative**: `<swim-drawer open>` plus `show()` / `hide()` on the element reference.
- **Imperative**: `openDrawer(options)` from `@swimlane/swim-ui` (or the drawer controller). Options: `direction`, `size`, `zIndex`, `closeOnOutsideClick`, `isRoot`, `parentContainer`, `content` (HTMLElement | DocumentFragment | string), `cssClass`. Returns `{ close(), drawer }`. Listen to the drawer’s `close` event for cleanup.

```js
import { openDrawer } from '@swimlane/swim-ui/drawer';  // or from the CDN bundle if it exports it
const { close, drawer } = openDrawer({ direction: 'left', size: 80, content: fragmentOrElement });
// later: close();
```

When using the CDN bundle, the drawer may be created with `document.createElement('swim-drawer')`, set properties, append content, append to body, then call `drawer.show()` and on `close` remove from DOM. See `projects/swimlane/swim-ui/src/components/drawer/drawer-controller.ts`.

## Component list (quick reference)

| Tag | Purpose |
|-----|--------|
| swim-button | Buttons: variant, size, disabled, state (active/in-progress/success/fail), promise |
| swim-button-group | Group of buttons; orientation, variant |
| swim-button-toggle | Single toggle button |
| swim-button-toggle-group | Toggle group; single selection, value-change |
| swim-input | Text/number/textarea; label, hint, validation, appearance, prefix/suffix slots |
| swim-select | Single/multi select; options prop or swim-option children; filter |
| swim-checkbox | Checkbox; indeterminate; change, checked-change |
| swim-radio | Single option |
| swim-radio-group | Radios; change with value |
| swim-toggle | Toggle switch; change |
| swim-slider | Slider; single or range; change { value, percent } |
| swim-tabs | Tab container; vertical; appearance |
| swim-tab | Tab panel; label slot; active |
| swim-section | Collapsible section; section-title, section-collapsed, section-collapsible, header slot |
| swim-card | Card; orientation, status, selectable, selected, outline-text |
| swim-card-header, swim-card-body, swim-card-footer, swim-card-avatar, swim-card-placeholder | Card structure |
| swim-dialog | Modal; dialog-title, format (regular/medium/large), visible, show-backdrop, close-button, close-on-blur, close-on-escape |
| swim-large-format-dialog-content, swim-large-format-dialog-footer | Large/medium dialog layout slots |
| swim-drawer | Slide panel; direction (left/right/bottom), size, open, closeOnOutsideClick, isRoot; show()/hide() |
| swim-tooltip | Tooltip/popover; content, placement, alignment, type, show-event |
| swim-icon | Icons; font-icon, font-set (e.g. "lit"); alt for a11y |
| swim-navbar | Navbar; swim-navbar-item children; active-change |
| swim-list | List/table; columns, headerLabels, dataSource, column-layout, height, default-row-status; page-change, scroll |
| swim-progress-spinner | Spinner; mode, appearance; in-progress-icon, complete-icon, fail-icon slots |
| swim-split | Resizable split; swim-split-area, swim-split-handle children; handle fires drag / dblclick |
| swim-calendar | Calendar; change, day-key-enter |
| swim-date-time | Date/time input + picker; change, value-change, blur, focus |

## Design and accessibility

- Use **lit-elements as-is**: no extra visual styling (colors, borders, shadows, typography) on `swim-*`; only layout (flex, grid, spacing).
- Use design tokens where needed (e.g. `--spacing-16`, `--radius-4` from the demo).
- Preserve semantics and ARIA; ensure labels, focus, and keyboard behavior. See the generate-swimlane-lit-solution skill for full a11y and leak-free rules.

## Relationship to generate-swimlane-lit-solution

This skill is the **single source** for the swim-ui component list, CDN/base usage, design rules, and API (see reference.md). When the task is to **generate a full solution file** (single `.js` in `projects/swimlane/swim-ui/demo/solutions`), apply the **generate-swimlane-lit-solution** skill for output location, create vs update, WCAG, and no memory leaks; it references use-swim-ui for components and design.

## Detailed API reference

For per-component properties, events, slots, and enums, see [reference.md](reference.md) and the source under `projects/swimlane/swim-ui/src/components/<name>/`.
