@warky/svelix (0.19.3)
Installation
@warky:registry=https://git.warky.dev/api/packages/wdevs/npm/npm install @warky/svelix@0.19.3"@warky/svelix": "0.19.3"About this package
Svelix
@warky/svelix — a Svelte 5 component library built on Skeleton UI and Tailwind CSS v4, focused on workflow-heavy UI, data-rich views, and content tooling.
Install
pnpm add @warky/svelix
Usage
import { Button, Former, Gridler } from '@warky/svelix';
Components
Layout & Structure
| Export | Description |
|---|---|
Boxer, BoxerTarget |
Adaptive layout container with data-adapter support |
Portal |
Renders children outside the current DOM subtree |
ErrorBoundary |
Catches and displays component errors |
Mantine Ports & Layout
Cheatsheets in llm/; defaults via SvelixLayout.
| Export | Description | Doc |
|---|---|---|
SvelixLayout, setSvelixLayout, useSvelixLayout |
App-wide component defaults | MANTINE_PORTS.md |
Group, Stack, Breadcrumbs, Alert, Tour, AppShell, AspectRatio |
Mantine ports | MANTINE_PORTS.md |
Paner, PanerPane |
Resizable split panes | PANER.md |
NavigationProgress, nprogress, createNProgress, useNavigationProgress |
Top progress bar + store | NAVIGATION_PROGRESS.md |
Windowz, WindowzBar, WindowzProvider, windowz, createWindowzManager |
Floating windows, window manager, show/hide bar | WINDOWZ.md |
AreaChart, BarChart, LineChart, ScatterChart, PieChart, DonutChart |
Lazy-loaded LayerChart charts | CHARTS.md |
Schedule, DayView, WeekView, MonthView, YearView, AgendaView |
Calendar views | SCHEDULE.md |
Forms
| Export | Description |
|---|---|
Former, FormerButtonArea, FormerDrawer, FormerModal |
Form builder with modal/drawer variants |
createFormerState |
Reactive form state factory |
FormerResolveSpecAPI, FormerRestHeadSpecAPI |
API adapters for form data sources |
ButtonCtrl, IconButtonCtrl |
Button and icon-button form controls |
TextInputCtrl, TextAreaCtrl, PasswordInputCtrl |
Text input controls |
NumberInputCtrl, NativeSelectCtrl |
Number and select controls |
CheckBoxCtrl, SwitchCtrl |
Checkbox and toggle controls; CheckBoxCtrl supports checkbox or switch presentation and boolean, integer, or string values |
FileInputCtrl |
Single-file picker with a compact file-type or image thumbnail, filename, and size |
JsonCtrl |
JSON editor control with a dialog editor and preview |
DateTimeCtrl |
Date/time picker control |
CtrlFieldShell, InlineWrapper |
Field shell and inline layout wrapper for form controls |
Data Grids
| Export | Description |
|---|---|
Gridler, GridlerFull |
Feature-rich data grid / table |
GridlerResolveSpecAdapter, GridlerRestHeaderSpecAdapter |
Data adapters for Gridler |
SvarkGrid (legacy) |
SVAR grid — import from @warky/svelix/legacy/SvarkGrid |
SvarkResolveSpecAdapter, SvarkRestHeaderSpecAdapter (legacy) |
Data adapters for SvarkGrid, same subpath |
Tickboxes (row selection)
| Prop / API | Effect |
|---|---|
rowMarkers="checkbox" |
Tickbox column; click a box to tick/untick |
cellSelection={false} |
Cell/range/column selection off; only ticks select. Double-click a cell toggles its tick (no edit) |
selection |
Controlled: { type: "row", rows: number[] } / { type: "none" } |
onSelectionChange(sel, rows?) |
Selection state + row data |
onSelectedItemsChange(rows) |
Ticked row data; [] when none |
getSelectedRows() |
Ticked row data from component instance |
menuItems |
Add Tick All / Untick All / Invert entries (onselect, icon) |
Stories: GridlerFull → Tickboxes, TickboxesClickToTick.
Editing (GridlerFull)
| Prop | Effect |
|---|---|
enableEdit (default false) |
Master switch for cell editing (double-click, Enter, typing, paste). Off: double-click selects the row and fires onCellDblClick / onRowDblClick. Element attr: enable-edit |
readonly |
Still blocks edits when enableEdit is on |
column.editor |
Built-in editor: text number date datetime checkbox select textarea. Default inferred from format / cell kind, else text |
column.editorOptions |
select choices: string[] or { label, value }[] |
editorMinWidth / column.editorMinWidth |
Min editor width (px); editors in narrow columns grow past the cell, kept inside the grid |
inplaceEditorFor(ctx) |
Return a snippet per cell from { cell, column, item, rowData, editorType }; undefined = default |
inplaceEditor |
Catch-all snippet; gets { cell, column, item, rowData, editorType, options, initialValue, width, height, onComplete(value), onCancel() } |
| Editor keys | Enter commit, Esc cancel, Tab / Shift+Tab commit + move; focus returns to the grid |
| Commit value | Typed: number / boolean / string / null |
Server filters (GridlerFull, CardGrid columns)
| Column prop | Effect |
|---|---|
serverFilter: false |
Filter stays in the UI and filters; not sent to the server |
filterQuery(filter, { id, dataKey }) |
Returns { filters?, customOperators? } for the request; undefined = default conversion. Operators are renamed fq_<columnId>_<index>; a throwing callback skips that filter (console.warn) |
filterOptions(search) |
Promise<{ value, label }[]>; swaps the filter text input for a searchable select (Boxer, debounced). Stores value (the id) plus label; in / notIn store string[] + labels. Operators limited to equals, notEquals, in, notIn, isNull, isNotNull. filterQuery receives the id / array |
filterControl snippet |
Custom control in place of the value input; gets { column, op, value, label, labels, setValue(value, label?), apply() }. Wins over filterOptions |
serverSort: false |
Sorting stays in the UI and sortOrder; not sent to the server |
sortQuery(direction, { id, dataKey }) |
Returns { sort?, computedColumns? }; computedColumns[].expression is raw SQL, sort on it by name (names are not renamed, keep them unique); undefined/throw = default sort |
| Scope | Server data sources only; dataSource="local" ignores filterQuery |
readPage |
customOperators from extraOptions config and per call are concatenated |
Column features (GridlerFull, CardGrid) — see llm/GRID_COLUMNS.md
| Prop | Effect |
|---|---|
column.lookup / resolveLookup |
FK column shows relation.field via preload |
layout.columnPresets |
Column defaults + rank by id pattern |
column.filterSql |
SQL predicate builder per filter operator |
layout.menuIcons |
Override default menu icons by id (add edit delete view change) |
column.initiallyHidden |
Hidden at start; toolbar Columns menu; persisted |
refresh({ select }), selectRecord(id) |
Reload / select + scroll |
valueLabels, exportRaw |
Value to label mapping; raw export |
hotfields |
Extra requested fields, not displayed |
Card Grid
| Export | Description |
|---|---|
CardGrid, DefaultCard, CardGridFilterPanel |
Filterable, sortable card grid |
Menus & Overlays
| Export | Description |
|---|---|
BetterMenu, MenuRenderer |
Enhanced dropdown menu |
createBetterMenuStore |
Store factory for menu state |
OverlayStack |
Stacked modal/overlay manager; async back veto, getOverlays / closeAllOverlays |
useSvelixOverlays |
Reactive list + close-all of open dialogs/drawers (SvelixLayout) |
ConfirmDialog, confirmDialog() |
Themed confirm dialog (replaces window.confirm) |
Content & Markup
| Export | Description |
|---|---|
ContentEditor |
Rich content editor (Carta Markdown + Monaco) |
TextEditor, MarkdownViewer, MonacoEditor |
Text, Markdown, and code editing components |
CollaboraEditor, Office365Editor |
Office document editor integrations |
ImageViewer, AudioPlayer, VideoPlayer, PdfViewer |
File media and PDF viewers |
EmailViewer, ZipViewer, UnknownFile |
Fallback file viewers |
Trees
| Export | Description |
|---|---|
VTree |
Virtualised tree view |
VTreeResolveSpecAdapter |
Data adapter for VTree |
Global State
| Export | Description |
|---|---|
GlobalStateStoreProvider |
App-level state provider |
useGlobalStateStoreContext |
Context accessor |
t, _T, loadTranslations, appendTranslations, etc. |
i18n helpers |
Utilities & Misc
| Export | Description |
|---|---|
Button |
Base button component |
CaptureScreenshotComponent, CaptureScreen |
Screenshot capture |
errorManager |
Global error manager |
IconAdd, IconClose, IconEdit, IconSearch, etc. |
SVG icon components |
CSS Assets
Tailwind CSS source and theme files are published under @warky/svelix/css/:
import '@warky/svelix/css/tailwind-source.css';
import '@warky/svelix/css/svelix_orange.css';
Web Components
A pilot subset of components is also published as standalone custom elements (<svelix-iframe>, <svelix-screenshot>, <svelix-error-boundary>, <svelix-dialog>, <svelix-drawer>, <svelix-grid>), usable from any framework or a plain HTML page with no build step. See them live in Storybook under Elements/ (pnpm storybook), or in tests-elements/fixtures/ for no-bundler examples.
<link rel="stylesheet" href="node_modules/@warky/svelix/dist/elements/elements.css" />
<script type="module" src="node_modules/@warky/svelix/dist/elements/register.js"></script>
<svelix-iframe frame-title="My iframe" src="https://example.com" width="100%" height="400"></svelix-iframe>
<svelix-dialog title="My dialog" close-on-esc="false">
<p>Dialog body content, projected as light-DOM children.</p>
</svelix-dialog>
import '@warky/svelix/elements/elements.css';
import '@warky/svelix/elements/register';
register pulls in all five tags; import a single one from @warky/svelix/elements/svelix-dialog (and so on per tag) to skip the rest. TypeScript declarations for the tags and their methods ship with the register export.
Stylesheets
| Import | Use when |
|---|---|
elements/elements.css |
The page is yours. Full Tailwind build including preflight. |
elements/elements-scoped.css |
Dropping the components into a page that already has its own styles. |
elements.css contains Tailwind's preflight, which is a global reset - on an existing site it strips heading sizes, list markers and default margins from your own markup. elements-scoped.css omits preflight (Skeleton's component styling does not depend on it) and leaves the host page alone; the components then inherit the host page's typography, so they will not look pixel-identical.
Either stylesheet also hides <svelix-dialog>/<svelix-drawer> while the tag is still undefined, so a server-rendered dialog body does not flash as ordinary page content before the bundle upgrades it.
Attributes
Multi-word props use kebab-case attributes: allowed-origins, ready-message-type, target-origin, content-class, positioner-class, close-on-esc.
<svelix-iframe> forwards to the inner <iframe> via frame-id, frame-title and frame-style - not id/title/style, which stay the host element's own and behave normally (el.style.opacity = ... works).
Attributes meaning "off" take a string: close-on-esc="false", show-preview="false". Only allowfullscreen and open are presence-style boolean attributes - for those, Svelte's coercion is presence-based, so any value including "false" means true.
open on <svelix-dialog>/<svelix-drawer> is reflected, so it tracks both ways - set or remove the attribute to open and close, and read it back after the user closes. So are total and loading on <svelix-grid>, which makes load state styleable with no JS: svelix-grid[loading] { opacity: 0.6 }.
<svelix-grid>
Wraps GridlerFull. Structured props are written as JSON attributes, or assigned as real values to the element property (el.columns = [...], or a () => Promise<Row[]> for async local data): columns, data, data-source-options, filters, sort-order, settings, menu-items, search-columns, selected-items, use-push-event-options.
An attribute that is not valid JSON does not stop the element mounting. It is reported three ways, because no one of them reaches every consumer: a console error, a svelix-error event (detail.attribute, detail.message), and the data-svelix-error attribute listing the attributes that failed - the only signal a script that ran after mount can still read.
<svelix-grid
height="400"
columns='[{"id":"name","title":"Name","width":200},{"id":"role","title":"Role","width":180}]'
data='[{"id":1,"name":"Ada Lovelace","role":"Analyst"}]'
></svelix-grid>
Server mode goes through data-source plus data-source-options, whose extraOptions carries the ResolveSpec query options - preload, omit_columns, computedColumns, customOperators, parameters, filters, sort, fetch_row_number:
<svelix-grid
data-source="resolvespec"
page-size="50"
unique-id="employee_id"
server-side-search
search-columns='["name","role"]'
columns='[{"id":"name","title":"Name","width":200}]'
data-source-options='{
"url": "https://api.example.com/resolve",
"schema": "hr",
"entity": "employees",
"authToken": "...",
"hotfields": ["department_id"],
"extraOptions": {
"preload": [{"relation": "department", "columns": ["id", "name"]}],
"omit_columns": ["secret"],
"computedColumns": [{"name": "full_name", "expression": "first || last"}],
"parameters": [{"name": "region", "value": "emea"}]
}
}'
></svelix-grid>
Grid methods: refresh(), getSelectedRows(), getLoadedData(). Grid events: svelix-rowclick, svelix-rowdblclick, svelix-celldblclick, svelix-celledited, svelix-rowcontextmenu, svelix-selectionchange, svelix-search, svelix-filterchange, svelix-sortchange, svelix-columnschange, svelix-datachange, svelix-menuselect, svelix-loaderror, svelix-error.
dataSourceOptions.headerssets custom HTTP headers on every request (requires@warkypublic/resolvespec-js>= 1.0.2).authTokenstill wins forAuthorization, and HeaderSpec query headers win over same-named custom headers.
Events
Callbacks are exposed as bubbling CustomEvents: svelix-ready, svelix-load, svelix-error, svelix-message, svelix-close, svelix-requestclose, svelix-report, svelix-reset, svelix-retry, svelix-capture (detail.dataUrl - a PNG data URL, or "" if the capture failed or was dismissed).
Two lifecycle events exist for non-Svelte hosts:
-
svelix-mounted- the inner component has mounted and the imperative methods (reload(),navigate(),sendMessage(),handleError(), ...) are callable. They do not exist on the element until then, andcustomElements.whenDefined()does not help because it resolves on definition, not instantiation. The event fires once, so check thedata-svelix-mountedattribute first if your script may run after mount:const ready = (el) => el.hasAttribute('data-svelix-mounted') ? Promise.resolve() : new Promise((r) => el.addEventListener('svelix-mounted', r, { once: true })); -
svelix-children-mounted- projected light-DOM children have been (re-)attached, with the container inevent.detail.container. Children are detached on connect and only reappear once the component mounts, so a scanner that walks the DOM synchronously after inserting markup - htmx's post-swapprocessNode, Alpine, Stimulus - never sees them. The container is passed explicitly becauseDialog/Drawerrender into a portal outside the host:<svelix-dialog title="Details" hx-on:svelix-children-mounted="htmx.process(event.detail.container)"> <button hx-get="/fragment" hx-target="#out">Load</button> </svelix-dialog>
Former and CardGrid are not yet part of this pilot.
LLM Documentation
Extended architecture and implementation docs are published with the package under @warky/svelix/llm/:
node_modules/@warky/svelix/llm/README.md
node_modules/@warky/svelix/llm/ARCHITECTURE.md
node_modules/@warky/svelix/llm/COMPONENT_GUIDE.md
node_modules/@warky/svelix/llm/FORMER_CONTROLLERS.md
node_modules/@warky/svelix/llm/MANTINE_PORTS.md
node_modules/@warky/svelix/llm/OVERLAYS.md
node_modules/@warky/svelix/llm/GRID_COLUMNS.md
node_modules/@warky/svelix/llm/Former.md
node_modules/@warky/svelix/llm/WINDOWZ.md
node_modules/@warky/svelix/llm/NAVIGATION_PROGRESS.md
Development
pnpm dev # SvelteKit dev server
pnpm storybook # Storybook on port 6006
pnpm build # Build package
pnpm test # Run unit tests
pnpm check # Type-check .svelte files
pnpm lint # ESLint
Dependencies
Dependencies
| ID | Version |
|---|---|
| @cartamd/plugin-anchor | ^2.2.0 |
| @cartamd/plugin-attachment | ^4.2.0 |
| @cartamd/plugin-code | ^4.2.0 |
| @cartamd/plugin-component | ^1.1.2 |
| @cartamd/plugin-emoji | ^4.3.0 |
| @cartamd/plugin-math | ^4.3.1 |
| @friendofsvelte/tipex | ^0.3.1 |
| @js-temporal/polyfill | ^0.5.1 |
| @svar-ui/svelte-grid | ^2.7.5 |
| @zag-js/color-picker | 1.46.0 |
| @zag-js/focus-trap | ^1.46.0 |
| @zag-js/pin-input | 1.46.0 |
| @zag-js/popper | ^1.46.0 |
| @zag-js/svelte | 1.46.0 |
| carta-md | ^4.11.5 |
| d3-shape | ^3.2.0 |
| exceljs | ^4.4.0 |
| github-markdown-css | ^5.9.0 |
| isomorphic-dompurify | ^4.6.0 |
| katex | ^0.19.0 |
| layerchart | ^2.8.1 |
| monaco-editor | ^0.57.0 |
| rrule | ^2.8.1 |
| xml-formatter | ^3.7.0 |
Development Dependencies
| ID | Version |
|---|---|
| @changesets/cli | ^3.0.3 |
| @chromatic-com/storybook | ^5.5.1 |
| @eslint/compat | ^2.1.1 |
| @eslint/js | ^10.0.1 |
| @playwright/test | ^1.64.1 |
| @sentry/svelte | ^11.8.0 |
| @skeletonlabs/skeleton | ^5.0.1 |
| @skeletonlabs/skeleton-svelte | ^5.0.1 |
| @storybook/addon-a11y | ^10.6.2 |
| @storybook/addon-docs | ^10.6.2 |
| @storybook/addon-svelte-csf | ^5.1.5 |
| @storybook/addon-vitest | ^10.6.2 |
| @storybook/sveltekit | ^10.6.2 |
| @storybook/test | ^8.6.15 |
| @sveltejs/adapter-static | ^4.0.0 |
| @sveltejs/kit | ^3.1.0 |
| @sveltejs/package | ^3.0.1 |
| @sveltejs/vite-plugin-svelte | ^7.3.1 |
| @tailwindcss/vite | ^4.3.3 |
| @tanstack/svelte-virtual | ^3.13.47 |
| @types/d3-shape | ^3.2.0 |
| @types/node | ^26.6.5 |
| @vitest/browser-playwright | ^5.0.5 |
| @vitest/coverage-v8 | ^5.0.5 |
| @warkypublic/artemis-kit | ^1.1.0 |
| @warkypublic/resolvespec-js | ^1.0.2 |
| esbuild | ^0.28.2 |
| eslint | ^10.13.0 |
| eslint-plugin-svelte | ^3.23.1 |
| globals | ^17.13.0 |
| playwright | ^1.64.1 |
| publint | ^0.3.25 |
| storybook | ^10.6.2 |
| svelte | ^5.57.2 |
| svelte-check | ^4.7.7 |
| tailwindcss | ^4.3.3 |
| tslib | ^2.8.1 |
| typescript | npm:@typescript/typescript6@^6.0.0 |
| typescript-7 | npm:typescript@^7.0.0 |
| typescript-eslint | ^8.71.2 |
| vite | ^8.3.4 |
| vitest | ^5.0.5 |
Peer Dependencies
| ID | Version |
|---|---|
| @skeletonlabs/skeleton | ^5.0.1 |
| @skeletonlabs/skeleton-svelte | ^5.0.1 |
| @warkypublic/artemis-kit | ^1.1.0 |
| @warkypublic/resolvespec-js | ^1.0.2 |
| svelte | ^5.20.0 |
| tailwindcss | ^4.3.3 |