Vue
Install Plex UI for Vue 3. Add @plexui/vue, wire up the stylesheet, and configure your router in a Vite or Nuxt app.
@plexui/vue is the Vue 3 version of Plex UI. Its components have the same props, defaults, markup and styles as the React components in @plexui/ui, and both packages read their CSS from @plexui/styles. Every component page has a Vue tab next to React.
Prerequisites
- Vue 3.5 or later (install guide)
- Tailwind 4 (install guide)
Install steps
1. Install the package
npm install @plexui/vue @plexui/styles@plexui/styles holds the tokens, resets and component CSS modules. @plexui/vue depends on it too, but your own stylesheet and Vite config import it directly, so install it as a dependency of your app (strict installs such as pnpm do not expose a package's dependencies to the app).
2. Setup styles
Add the foundation styles and Tailwind layers to the top of your global stylesheet (e.g. main.css):
/* Pin the cascade-layer order so Plex UI's reset wins over Tailwind preflight
for form controls. */
@layer theme, base, components, utilities;
@import "tailwindcss";
@import "@plexui/styles/css";
/* Required for Tailwind to find class references in Plex UI components. */
@source "../node_modules/@plexui/vue";The @source path is relative to the stylesheet. The one above assumes it lives in src/.
On Vite, add the Plex UI plugin. It pins the CSS transformer and minifier so the layer order survives the build, and injects the layer order into index.html as a failsafe:
// vite.config.ts
import vue from "@vitejs/plugin-vue";
import plexui from "@plexui/styles/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [vue(), plexui()],
});The Installation guide explains the layer order, the Lightning CSS caveats and the optional Tailwind theme import in detail. They apply to Vue unchanged; replace @plexui/ui/css with @plexui/styles/css and @plexui/ui/vite with @plexui/styles/vite.
Then import your stylesheet before mounting the app:
// main.ts
import "./main.css";
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");3. Server-side rendering
Components import their CSS modules from @plexui/styles, which Node cannot load on its own. When you render on the server, let your bundler process @plexui/vue instead of loading it from node_modules:
// vite.config.ts (SSR)
export default defineConfig({
plugins: [vue(), plexui()],
ssr: { noExternal: ["@plexui/vue", "@plexui/styles"] },
});In Nuxt, add it to build.transpile and register the stylesheet (keep the @layer line at its top, since Nuxt does not use index.html):
// nuxt.config.ts
import plexui from "@plexui/styles/vite";
export default defineNuxtConfig({
css: ["~/assets/css/main.css"],
build: { transpile: ["@plexui/vue"] },
vite: { plugins: [plexui()] },
});Point @source at node_modules from that file: ../../node_modules/@plexui/vue for assets/css/main.css (Nuxt 3), or ../../../node_modules/@plexui/vue for app/assets/css/main.css (Nuxt 4).
4. Configure router (optional)
<PlexUIProvider> sets the default link component used by <TextLink>, <ButtonLink> and other components that render links. Pass RouterLink (or NuxtLink in Nuxt):
<script setup lang="ts">
import { RouterLink, RouterView } from "vue-router";
import { PlexUIProvider } from "@plexui/vue/components/PlexUIProvider";
</script>
<template>
<PlexUIProvider :link-component="RouterLink">
<RouterView />
</PlexUIProvider>
</template>Card, ButtonLink and TextLink pass their href to a link component that declares a to prop (such as RouterLink or NuxtLink) as to, so <TextLink href="/settings"> navigates through the router. Other link components receive href.
Start building
<script setup lang="ts">
import { ref } from "vue";
import { Badge } from "@plexui/vue/components/Badge";
import { Button } from "@plexui/vue/components/Button";
import { Input } from "@plexui/vue/components/Input";
import { Search, Sparkles } from "@plexui/vue/components/Icon";
const query = ref("");
</script>
<template>
<div class="flex items-center gap-3">
<Input v-model:value="query" placeholder="Search">
<template #startAdornment><Search /></template>
</Input>
<Button color="primary"><Sparkles /> Generate</Button>
<Badge color="success">New</Badge>
</div>
</template>From React to Vue
Component names, props and defaults are the same as in React. The differences follow Vue conventions:
| Prop | Type | Default | Description |
|---|---|---|---|
className | class | — | Classes go on the same element as in React |
value + onChange | v-model:value | — | Controlled values use a `value` prop and an `update:value` event. Other controlled props work the same way, e.g. `v-model:open` on Dialog |
onX callbacks | @x listeners | — | For example `onClick` is `@click` and `onOpenChange` is `@update:open` |
ReactNode props | slots | — | Content props are slots, e.g. `#startAdornment`; most also accept a plain string prop |
Dialog.Trigger | DialogTrigger | — | Compound parts are flat named exports from the same module |
Hooks | composables | — | One module per hook, e.g. `useSimulatedProgress` from `@plexui/vue/composables/useSimulatedProgress` |
Icons have the same names as in React and import from @plexui/vue/components/Icon.