There is no separate package to install for Nuxt. The module is an export of the library itself, and this documentation site runs on it. A Tailwind v4 app needs one option:
import { TAILWIND_V4_LAYERS } from 'bitboss-ui/nuxt';
export default defineNuxtConfig({
modules: ['bitboss-ui/nuxt'],
bitboss: {
cssLayers: TAILWIND_V4_LAYERS,
},
});
The module puts the stylesheet in the server render itself, so the first paint
is styled, and turns the browser injection off. With cssLayers it sits in a
layer below your utilities; without, it sits above your CSS where the injection
put it. You add no css entry and no @layer line. Plain CSS or Tailwind v3:
drop the option and read Installation.
The module ships with the library
bitboss-ui/nuxt pushes the library's Vite plugin into the Nuxt build and adds
the runtime plugin. With autoImport on, it also registers the components and
composables with Nuxt's auto-imports. Its config key is bitboss, and it takes
the Vite plugin's options plus the Nuxt-only autoImport. A project moving
between Vite and Nuxt moves its config across unchanged.
Leave autoImport off, which is the default. Explicit imports keep
vueCompilerOptions.checkUnknownComponents able to fail the build on a
mistyped or removed Bb* tag. Turn it on to move an app off bitboss-nuxt
without adding every import in the same commit.
true registers the components and the composables, BbForm,
useBbFormContext and useBbFormField included; { composables: false }
keeps only the components. It never shadows a component of your own with the
same name: a ~/components/BbButton.vue keeps winning. It also never registers
the library's useId, because Nuxt already auto-imports Vue's. Import the
library's explicitly if you want it.
The module mounts no component for you. confirm(), toast() and on-demand
dialogs render in one <BbHost />, and in Nuxt that goes in app.vue, beside
the layout:
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
<BbHost />
</template>
<script setup lang="ts">
import { BbHost } from 'bitboss-ui';
</script>
It renders nothing on the server, so it hydrates without a mismatch. Nuxt shows
error.vue in place of app.vue, so an error page that fires a toast or a
confirm mounts its own <BbHost />. This site's app.vue is the one above.
Options in the bitboss key
The bitboss key takes every option of bitbossUi(). The ones most apps set are
in the options list on Installation, with
their defaults. A few read differently in Nuxt:
cssLayerslayers the stylesheet the module adds to the server render, as above.injectStylesgoesfalseonly when you listbitboss-ui/styles.cssincssyourself.iconDirresolves fromapp/, see below.localeis English by default, and an Italian app setslocale: 'it'. For a per-request locale, calluseBbConfig().setConfig({ locale })insidenuxtApp.vueApp.runWithContext()from a plugin of your own.nuxtLinkNamenames the component that renders router links,'NuxtLink'by default.ptandptScopestake the same maps as in Vite. ImportdefinePtfrombitboss-ui/nuxt, see Passthrough.
Two options write files on your machine when the dev server starts, and each
logs what it changed. vscodeSettings is on by default: it edits
.vscode/settings.json, keeping comments, formatting and key order, and
vscodeSettings: false stops it. mcp is off by default: set it to true and
dev writes the server into .mcp.json, .cursor/mcp.json and
.vscode/mcp.json, leaving any other servers alone. That is the registration
npx bitboss-ui ai-init does, except that it never installs anything, so run
ai-init once for the server's peers. See AI agents.
Registering variants
The variant registries are plugin options too, so in Nuxt they live in the same
bitboss block:
bitboss: {
buttonVariants: ['success'],
}
A list adds to the built-in names. Leaving one out does not remove it.
Registering the name makes it type-check once the plugin has written
app/bitboss-ui.d.ts (commit it). npx bitboss-ui check writes the same file
without starting the dev server. You still own the variant's CSS; see
Design language, which covers both
halves and what happens if you do only one.
The registries are buttonVariants, badgeVariants, alertVariants,
indicatorVariants, toastVariants, confirmVariants,
dropdownItemVariants, tooltipVariants, inputVariants for the text-like
form controls, and tabsVariants for BbTabs.
Icons in Nuxt
iconDir is resolved from the Vite root, which in Nuxt 4 is app/: leave the
default './assets/icons', which already means app/assets/icons
(Installation shows what './app/assets/icons'
breaks). The build also scans the whole project for provider names (lucide:save), not
only app/, so a name written in server/ or content/ still ships.
Everything else about naming, the build-time literal scan, and where components
already accept an icon is in Icons.
Prerendering and SSR
The components server-render, and the module bundles the library into the
server build for you. This site runs nuxt generate with failOnError enabled
and does not wrap library components in ClientOnly.
The server cannot measure the screen, so it renders for ssrViewportWidth
(1024 by default): a mobile visitor's first paint is desktop-shaped and adjusts
once the client measures. If most of your readers are on phones, set it lower in
the bitboss key, for example ssrViewportWidth: 768.
Two things to know when a page fetches its own options:
prefill: trueonBbSelectruns your provider once, inonServerPrefetch. The rows travel to the browser in the Nuxt payload, so the selection is already in the server-rendered HTML and the client does not fetch again. The module installs the adapter that carries them. Return plain, serializable rows: objects, arrays and dates, not class instances or ORM models.- The default
'interaction'defers the load to the client, which is usually what you want and is why it is the default.
Only that first load travels. A search the user types, a dependencies change
and a page change in BbTable all fetch in the browser. In dev, a warning that
useId() differs between server and client means an onServerPrefetch of your
own, which Nuxt strips from the production client build. Load that data with
useAsyncData instead.
Fetching data has the full matrix.
On a static site the reader's theme is not knowable at build time. Apply the
class from an inline script in head before hydration, or the first paint
flashes the wrong theme. Design tokens
explains why color-scheme follows the class rather than the OS preference.
If you have bitboss-nuxt installed
@bitboss-dev/bitboss-ui-nuxt is a separate, v2-era package. It predates
this module, and its API shows it: unprefixed icon names, a components.validation
switch, and BaseButton rather than
BbBaseButton.
Migrating off it is mostly deletion:
- Remove
@bitboss-dev/bitboss-ui-nuxtfrommodulesand frompackage.json, and add'bitboss-ui/nuxt'. - Move
icons.pathtoiconDir,styles.enabledtoinjectStyles,link.nametonuxtLinkNameandcomponents.requiredAsterisktorequiredAsterisk, which now defaults totrue. Dropicons.enabled,styles.index,link.enabledandlogLevel: v3 has no equivalent. - Drop
componentsandcomposables. Import what each template uses, or setautoImport: trueuntil you have added the imports. Its default flipped: the old module auto-imported, this one does not. - Prefix your own icon names with
local:, which v3 requires. See Icons. - Drop
components.validation. The form controls validate inside aBbFormwith no switch; see Validated forms.
Then work through Migrating from v2, because a project on that module is on v2 of the library as well.