Getting Started

Installation

Install @vyui/core and @vyui/kit into a Vue-Lynx app.

Setup

Add to a Vue-Lynx project

Install the @vyui/core package

pnpm add @vyui/core

Use a primitive

Primitives are unstyled. Compose them with your own classes, tokens, or design system.

App.vue
<script setup>
import { SliderRoot, SliderTrack, SliderRange, SliderThumb } from '@vyui/core'
import { ref } from 'vue'

const value = ref(50)
</script>

<template>
  <SliderRoot v-model="value" :max="100">
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
  </SliderRoot>
</template>

Add styled components with @vyui/kit

Install both packages

pnpm add @vyui/core @vyui/kit

@vyui/kit depends on @vyui/core, but it does not re-export the full core surface. Import styled Vy* components from kit, and import raw primitives or utilities directly from core unless the kit docs call out a specific Vy* convenience alias.

Configure Tailwind

@vyui/kit ships its styling as a Tailwind preset. Add it alongside the Lynx preset, and feed the kit ui-* state markers into the Lynx preset's uiVariants plugin — the class-based replacements for Lynx-incompatible data-[state] selectors. Without this step components render unstyled.

tailwind.config.ts
import type { Config } from 'tailwindcss'
import { createLynxPreset } from '@lynx-js/tailwind-preset'
import { createVyuiPreset, VYUI_UI_STATES } from '@vyui/kit/tailwind'

const lynxPreset = createLynxPreset({
  lynxUIPlugins: {
    uiVariants: {
      prefixes: defaults => ({ ...defaults, ui: [...defaults.ui, ...VYUI_UI_STATES] }),
    },
  },
})

export default {
  // Scan the kit + core component sources so their utility classes aren't purged.
  content: [
    './src/**/*.{vue,js,ts}',
    './node_modules/@vyui/kit/dist/**/*.js',
    './node_modules/@vyui/core/dist/**/*.js',
  ],
  presets: [lynxPreset, createVyuiPreset()],
} satisfies Config

Import the theme stylesheet

@vyui/kit/style.css defines the default design tokens using Tailwind theme() calls, so pull it in through your Tailwind pipeline with a CSS @import — not a plain JS import. Put any --ui-color-* overrides after it.

src/index.css
@tailwind base;
@tailwind utilities;

/* @vyui/kit default theme tokens — overrides go below this line. */
@import '@vyui/kit/style.css';

Register Vy UI

Vy UI needs its theme config provided once at your app entry. On Vue-Lynx — the primary target — do this with provideVyUI and import components by name where you use them, so the bundler only pulls what you reference. Kit's defaults use lucide icons, so register that set up front, and install the Intl polyfill for Lynx's PrimJS engine.

src/index.ts
import { createApp } from 'vue-lynx'
import { installIntlPolyfill, registerIconSet } from '@vyui/core'
import { provideVyUI } from '@vyui/kit'
import lucide from '@iconify-json/lucide/icons.json'
import App from './App.vue'
import './index.css'

installIntlPolyfill()
registerIconSet('lucide', lucide)

const app = createApp(App)
provideVyUI(app)
app.mount()

Then import components where you use them:

SomeScreen.vue
<script setup>
import { VyButton } from '@vyui/kit'
</script>

<template>
  <VyButton>Tap me</VyButton>
</template>
On full Vue (web) you can instead call app.use(VyUI), which registers every Vy* component globally so <VyButton> works without an import — convenient, but it pulls the entire component set into your bundle. Vue-Lynx's createApp has no app.component, so app.use(VyUI) degrades to theme-only there (with a dev warning) — provideVyUI + named imports is the native path. Register just a subset globally with app.use(VyUI, { components: { VyButton } }).

Runtime modes

@vyui/kit runs on any Vue-compatible runtime, but only some expose app.component. Pick the entry that matches yours:

RuntimeEntryComponents
Vue-Lynx / minimal (native path)provideVyUI(app, config)Local imports (import { VyButton } from '@vyui/kit')
Full Vue (web)app.use(VyUI, config)Registered globally
Build (Tailwind)createVyuiPreset(config)— (generates the class surface)

Vue-Lynx's createApp has no app.component, so app.use(VyUI) degrades to theme-only there (with a dev warning) — provideVyUI is the blessed native path. Runtime config selects from the classes Tailwind already emitted; it never creates styling.

Single-source config with defineVyuiConfig

The color set is meaningful to both planes: the Tailwind preset must generate the classes, and the runtime must select the same set. Author it once with defineVyuiConfig (from the light @vyui/kit/config entry — safe to import in a Tailwind config; it never pulls component code) and feed the result to both:

vyui.config.ts
import { defineVyuiConfig } from '@vyui/kit/config'

export default defineVyuiConfig({
  theme: {
    primary: 'orange',
    gray: 'stone',
    colors: ['primary', 'secondary', 'success', 'info', 'warning', 'error'],
  },
  components: {
    button: { slots: { base: 'rounded-xl' } },
  },
})
tailwind.config.ts
import vyuiConfig from './vyui.config'
import { createVyuiPreset } from '@vyui/kit/tailwind'

export default {
  presets: [lynxPreset, createVyuiPreset(vyuiConfig)],
}
src/index.ts
import vyuiConfig from './vyui.config'
import { provideVyUI } from '@vyui/kit' // or: app.use(VyUI, vyuiConfig) on web

provideVyUI(app, vyuiConfig)

Mount the overlay & toast hosts

VyModal, VyDrawer, VyPopover and friends render into a portal host, and VyToast needs a toast provider — the plugin does not wire these up for you. Mount both once near the root:

App.vue
<script setup>
import { OverlayRoot, ToastProvider } from '@vyui/core'
</script>

<template>
  <ToastProvider>
    <!-- your app -->
  </ToastProvider>
  <!-- Portal host for overlays; keep it a sibling at the app root. -->
  <OverlayRoot />
</template>

Use a Vy* component

App.vue
<script setup>
import { VyButton, VySlider } from '@vyui/kit'
import { ref } from 'vue'

const value = ref(50)
</script>

<template>
  <VySlider v-model="value" :max="100" />
  <VyButton variant="solid" color="primary">Save</VyButton>
</template>

Options

Kit ships sensible defaults — you only need to reach for these when you want to override theme tokens, swap a primary color, or change a component's default variant.

theme

Pass component overrides under ui.<component> to deep-merge them into the default Tailwind Variants theme. Every Vy* component reads from this — no rebuild required. Like Nuxt UI, everything lives under the single ui namespace.

src/index.ts
createApp(App).use(VyUI, {
  ui: {
    button: {
      defaultVariants: { color: 'primary' },
    },
  },
})

colors

Override the semantic color slots (primary, secondary, success, info, warning, error, neutral) by redefining the --ui-color-{semantic}-{shade} CSS variables in your own stylesheet.

src/app.css
:root {
  --ui-color-primary-500: #6366f1;
  --ui-color-primary-600: #4f46e5;
}

Adding a custom color

The configurable color set (primary, secondary, success, info, warning, errorneutral is always appended) is extensible. Declare the extra color once in your shared config so the build (which generates the classes) and the runtime (which selects them) can't drift:

vyui.config.ts
import { defineVyuiConfig } from '@vyui/kit/config'
import { COLORS } from '@vyui/kit/tailwind'

export default defineVyuiConfig({
  theme: { colors: [...COLORS, 'tertiary'] },
})

Pass that same object to createVyuiPreset(vyuiConfig) and provideVyUI(app, vyuiConfig) as shown above. createVyuiPreset dev-warns if you list a color it can't back with a --ui-color-* var, so a "class resolves to nothing" mistake surfaces at build time. To also type-check tertiary on every component's color prop:

vyui-colors.d.ts
declare module '@vyui/kit' {
  interface VyuiColorRegistry { tertiary: true }
}

Then add the --ui-color-tertiary-{50..950} CSS-var block (the .d.ts + CSS can be generated with node node_modules/@vyui/kit/scripts/gen-colors.mjs --colors tertiary=indigo). See the @vyui/kit README for the full flow.

Prefer copying component source into your app? Use the Vy UI CLI to initialize a registry-backed setup and add individual components.