Vue
Install and compiler configuration
Section titled “Install and compiler configuration”pnpm add @timelessui/componentsTell the Vue compiler that ui- tags are custom elements:
vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('ui-') } } })Then import the Vue declarations once in your application types:
import '@timelessui/components/vue'They register every ui-* tag on GlobalComponents, so vue-tsc checks attributes and their
permitted values in templates. Vue camelizes a dashed event name, so ui-change binds as
@ui-change in a template and is typed as onUiChange. The declaration is types-only and adds no
runtime code and no Vue dependency.
CSS and registration
Section titled “CSS and registration”Import granular CSS and registration from a client entrypoint:
import '@timelessui/components/css/tokens.css'import '@timelessui/components/css/listbox.css'import '@timelessui/components/define/ui-listbox'Markup and state
Section titled “Markup and state”Use attributes for authored defaults and DOM properties for live state:
<ui-listbox ref="listbox" value="draft" role="listbox" aria-label="Status"> <div role="option" data-ui-value="draft">Draft</div> <div role="option" data-ui-value="ready">Ready</div></ui-listbox>SSR, hydration, events, and TypeScript
Section titled “SSR, hydration, events, and TypeScript”Vue can hydrate the server-rendered Light DOM before the element definition upgrades it. Keep registration in browser code. Use a typed template ref to assign properties, and bind namespaced events in the template:
<ui-listbox value="draft" role="listbox" aria-label="Status" @ui-change="onChange"> <div role="option" data-ui-value="draft">Draft</div></ui-listbox>Each element’s events carry the detail type it actually dispatches, so onChange receives a
CustomEvent<ListboxChangeDetail>. Public element classes and detail types import without
registering anything on the server.
For CSS-only components, which are a root class plus data-ui-* on a native tag, bind the typed
helper instead of writing the attributes by hand:
<script setup lang="ts">import { uiAttributes } from '@timelessui/components/attributes'</script>
<template> <button v-bind="uiAttributes('button', { variant: 'primary' })" type="button">Publish</button></template>