Skip to content

Svelte

Terminal window
pnpm add @timelessui/components

Import the Svelte declarations once in your application types:

import '@timelessui/components/svelte'

They extend svelteHTML.IntrinsicElements, so svelte-check knows every ui-* tag and the values each attribute accepts. Both event spellings are declared — Svelte 5 onui-change and Svelte 4 on:ui-change — so the same declaration checks either version. It is types-only and adds no runtime code and no Svelte dependency.

Import CSS and definitions from a client module or layout:

import '@timelessui/components/css/tokens.css'
import '@timelessui/components/css/tabs.css'
import '@timelessui/components/define/ui-tabs'

Author the element normally:

<ui-tabs value="details">
<div role="tablist" aria-label="Project">
<button role="tab" value="details">Details</button>
<button role="tab" value="activity">Activity</button>
</div>
<section role="tabpanel">Project details</section>
<section role="tabpanel">Recent activity</section>
</ui-tabs>

SSR emits the complete Light DOM anatomy before the definition loads. Plain attributes express authored defaults. Bind namespaced events directly, and use bind:this when you need to assign live properties:

<ui-tabs value="details" onui-change={(event) => console.log(event.detail.value)}>
<!-- tablist and panels -->
</ui-tabs>

The handler receives a CustomEvent<TabsChangeDetail>, because each element declares the detail type it dispatches rather than sharing one generic signature. Element classes and detail types import into TypeScript without registering anything on the server.

CSS-only components are a root class plus data-ui-* on a native tag, which Svelte cannot check per element. Spread the typed helper instead:

<script lang="ts">
import { uiAttributes } from '@timelessui/components/attributes'
</script>
<button {...uiAttributes('button', { variant: 'primary' })} type="button">Publish</button>