--- 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//`. 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//*.component.ts` for the exact list. ## Imperative APIs ### Drawer - **Declarative**: `` 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//`.