SSR / Nuxt Notes
Every component in @luxeanor/ui follows an SSR-safety discipline and works out of the box in Nuxt 3 / VitePress and other server-rendered environments (this docs site itself is built as SSG).
Guarantees inside the library
- Browser APIs only appear in
onMounted/ event handlers /watch— module top-level and synchronoussetupnever touchwindow/document/localStorage - Overlay components (Modal / Drawer / Dropdown / Select / Tooltip / Toast / Confirm) use
Teleporttobodywith a mounted guard (v-if="mounted"), so the server never renders overlay content — no hydration mismatch useThemereturns defaults under SSR and never reads/writes DOM or storage
What consumers should handle
1. Server-side theme attribute consistency
If server-rendered HTML lacks data-theme / data-mode, the first frame flashes the default theme. Two options:
- Fixed theme: hard-code the attributes in your server template /
htmlAttrs(e.g.useHead({ htmlAttrs: { 'data-theme': 'ink', 'data-mode': 'light' } })) - Follow user preference: inline the themeBootScript in
<head>so attributes land before CSS parses
2. How you consume the package
| Scenario | Mode | Extra config |
|---|---|---|
Regular project, npm i @luxeanor/ui | dist build (ESM + d.ts) | none |
Monorepo workspace:* source | raw .vue/.ts source | Nuxt needs build.transpile: ['@luxeanor/ui'] |
3. Client-only logic
Visual enhancers like useMouseVars and useReveal rely on IntersectionObserver / pointer events — the library already guards the environment, so they're no-ops under SSR and need no <ClientOnly>. The only thing that genuinely needs <ClientOnly> is a component whose first frame depends on localStorage (e.g. LxThemeSwitcher placed in server-rendered layout).