@bcc-code/component-library-vue

Extended Vue component library based on PrimeVue and BCC design tokens
56,535 2
Install
npm install @bcc-code/component-library-vue
Latest Version:1.5.3
Vue:3
License:Apache-2.0
Last Updated:Oct 22, 2026
Links: GitHub  ·  npm
Maintainer: karsten.kuepper

@bcc-code/component-library-vue

Vue 3 component library built on PrimeVue and BCC design tokens. You only need this package—no separate Tailwind or PrimeVue install.

Storybook Link

Install

pnpm add @bcc-code/component-library-vue
# or
npm install @bcc-code/component-library-vue
# or
yarn add @bcc-code/component-library-vue

Min requirements: Vue 3.

Note to PNPM installs: The library uses @bcc-code/icons-vue and @bcc-code/design-tokens. To use them in your own app (e.g. import { CheckIcon } from '@bcc-code/icons-vue') without needing to explicitly add install them in your own package.json, add this to your project’s .npmrc so pnpm hoists them:

public-hoist-pattern[]=@bcc-code/icons-vue
public-hoist-pattern[]=@bcc-code/design-tokens

Then run pnpm install again. With npm or Yarn this is not needed.

Quick start

  1. Register the library in your app (e.g. main.ts):
import { createApp } from 'vue';
import App from './App.vue';
import { BccComponentLibrary } from '@bcc-code/component-library-vue';

const app = createApp(App);
app.use(BccComponentLibrary);
app.mount('#app');
  1. Add styles using one of the two options below.

Styles Option 1 — Recommended: full Tailwind in your app

Use this if you want Tailwind utility classes in your own templates while still letting the library's components render correctly.

  1. Add the Tailwind Vite plugin (the package brings Tailwind in as a dependency; you only wire it up):
// vite.config.ts
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
	plugins: [vue(), tailwindcss()],
	// ...
});
  1. Import the theme in your main CSS file (e.g. src/main.css or src/assets/main.css):
@import '@bcc-code/component-library-vue/theme.css';
/* Optional, if not already included */
@import '@bcc-code/component-library-vue/archivo-font.css';

That single import is enough. theme.css includes:

  • BCC design tokens, @theme / @utility definitions, and the rest of the design-system CSS inlined from src/style.css (including component-specific rules such as BccInput icon sizing and BccButton context tokens).
  • library-utilities.css, the pre-compiled Tailwind utility class rules used inside library templates (which your build cannot infer from the published JS).

Do not rely on library-utilities.css alone with a minimal “base” import: you still need the full theme.css (or style.css for Option 2) so non-utility component styles and tokens are present.

Styles Option 2 — Pre-built CSS only

Use this if you don’t want Tailwind in your project and only need the library’s styles and components.

In your entry file (e.g. main.ts), before mounting the app:

import '@bcc-code/component-library-vue/style.css';

You get the BCC theme and component styles only; no Tailwind utilities in your app.

Brand color

The library uses the BCC teal as its brand color. An app outside the BCC profile can supply its own palette by redefining two ramps in its own CSS, after the library import. No configuration or build setup is needed — these are ordinary custom properties.

@import '@bcc-code/component-library-vue/theme.css';

/* Drives the semantic brand tokens: primary buttons, checkboxes and radio
   buttons, focus and selected states, links, and the bg-brand-* / text-brand-*
   Tailwind utilities. One set of values covers both color schemes — the
   semantic layer picks different steps in dark mode. */
:root {
	--color-brand-100: #eff6ff;
	--color-brand-200: #dbeafe;
	--color-brand-300: #bfdbfe;
	--color-brand-400: #93c5fd;
	--color-brand-500: #60a5fa;
	--color-brand-600: #3b82f6;
	--color-brand-700: #2563eb;
	--color-brand-800: #1d4ed8;
	--color-brand-900: #1e40af;
	--color-brand-1000: #172554;
}

/* Drives the ctx-brand-* context utilities. This ramp is mode-aware: step 100 is
   always the step furthest from the text color, so the dark values are the same
   palette in reverse. */
:root {
	--color-default-bcc-100: #eff6ff;
	--color-default-bcc-200: #dbeafe;
	--color-default-bcc-300: #bfdbfe;
	--color-default-bcc-400: #93c5fd;
	--color-default-bcc-500: #60a5fa;
	--color-default-bcc-600: #3b82f6;
	--color-default-bcc-700: #2563eb;
	--color-default-bcc-800: #1d4ed8;
	--color-default-bcc-900: #1e40af;
	--color-default-bcc-1000: #172554;
}

.dark {
	--color-default-bcc-100: #172554;
	--color-default-bcc-200: #1e40af;
	--color-default-bcc-300: #1d4ed8;
	--color-default-bcc-400: #2563eb;
	--color-default-bcc-500: #3b82f6;
	--color-default-bcc-600: #60a5fa;
	--color-default-bcc-700: #93c5fd;
	--color-default-bcc-800: #bfdbfe;
	--color-default-bcc-900: #dbeafe;
	--color-default-bcc-1000: #eff6ff;
}

The blocks have to come after the library's CSS so they win the cascade. In Option 1 that means putting them below the @import in your main CSS file; in Option 2, in a stylesheet loaded after style.css. Both are verified to work.

Naming note: --color-default-bcc-* keeps the bcc in its name because it is generated from the Figma token set, not because it has to hold BCC colors. Overriding it with your own palette is supported.

Skipping the second ramp leaves ctx-brand-* teal while everything else changes, which is usually not what you want.

Choosing values

Step 800 carries small text and primary button backgrounds, so check it against the contrast requirements in the Colors documentation — 4.5:1 against step 100 and against white. Supply a full light-to-dark range rather than ten shades of the same tone, since the mirrored dark ramp depends on it.

Components

All components are namespaced with Bcc. Use them in templates or register them globally in your main.ts.

Example:

<template>
	<div class="flex gap-4 p-4">
		<BccButton label="Save" />
		<BccInput v-model="name" placeholder="Name" />
	</div>
</template>

<script setup lang="ts">
import { BccButton, BccInput } from '@bcc-code/component-library-vue';
import { ref } from 'vue';

const name = ref('');
</script>

Example:

// main.ts
...
import { BccButton, BccInput } from '@bcc-code/component-library-vue';

// After app.use(BccComponentLibrary)
app.component('BccButton', BccButton);
app.component('BccInput', BccInput);

The library exports both custom BCC components (e.g. BccBadge, BccFrame, BccReact) and wrapped PrimeVue components (e.g. BccButton, BccDialog, BccDataTable). PrimeVue services (Toast, Confirm, Dialog) are configured by BccComponentLibrary; use the composables useToast, useConfirm, and useDialog from the library when you need them.

Bundle size

The ES build is tree-shakeable: you pay for the components you import, not for the whole library. Importing a single small component adds a few kB on top of Vue; heavier components (BccDataTable, BccEditor, BccDatePicker) cost proportionally more because they carry their PrimeVue implementation and styles.

Two things are needed on the consumer side:

  • Import from the package root and let your bundler shake it — import { BccBadge } from '@bcc-code/component-library-vue'. There is no need to deep-import individual files.
  • Build for production. Dev servers do not tree-shake, so pnpm dev will always look like the whole library is loaded.

Styles are not tree-shaken: style.css (Option 2) always contains the rules for every component. If CSS size matters, use Option 1 (theme.css + Tailwind in your app), where Tailwind only emits the utilities you actually use.


Development

pnpm install
pnpm run start        # Storybook on port 6006
pnpm run build        # Typecheck, types, and Vite build
pnpm run docs:ai      # Build Storybook, then generate AI-ready docs outputs
pnpm run build:llms   # Regenerate AI docs from an existing storybook-static/index.json
pnpm run build:vite   # Vite build only (includes theme.css)

Build output shape (do not flatten it)

vite build emits one file per module (output.preserveModules) rather than a single bundle, and package.json declares "sideEffects": ["**/*.css"]. Both are required for consumers to tree-shake the package, and either one alone does nothing — see #369.

The reason a single bundle cannot be shaken: PrimeVue's per-component style modules call BaseStyle.extend() and the theme preset calls definePreset() at module top level. Concatenated into one file, those become impure top-level statements that a consumer's bundler must keep, which dragged ~785 kB of unused code into every consumer bundle.

Consequences to keep in mind when touching the build:

  • Dependencies are bundled and re-rooted under dist/vendor/<package>/.... PrimeVue in particular must not be made external: the @primevue/icons patch that swaps in BCC icons only reaches consumers through our own build output.
  • preserveModules only supports the ES format, so the UMD bundle is built separately by vite.config.umd.ts.
  • pnpm run test:bundle-size bundles a probe app against dist and fails if importing one component costs more than 40 kB. It runs in CI after the build.

AI-ready docs outputs

pnpm run docs:ai generates the public AI documentation artifacts into storybook-static/:

  • /llms.txt: Markdown index of public docs pages.
  • /llms-full.txt: concatenated Markdown for all public docs pages.
  • /docs/<page>.md: per-page Markdown mirroring the Storybook docs route, e.g. /docs/foundations-colors--docs -> /docs/foundations-colors--docs.md.

build-storybook runs the same generation after Storybook builds, so deployed docs get these files at runtime. The generated files live in storybook-static/, which is ignored and not committed; CI does not need a drift check unless these build artifacts are committed later.

The generator uses Storybook's storybook-static/index.json as the route source of truth, converts MDX to readable Markdown, and summarizes autodocs story pages from story metadata. It only reads public docs entries from docs and src through the Storybook manifest, and excludes private/internal/secrets paths, env files, dependency folders, build outputs, and caches.

Override the published URL base with LLMS_BASE_URL=https://your-docs-host pnpm run build:llms if needed. Only static Markdown and JSON documentation artifacts are produced.

Folder structure (where to work)

  • src/components/custom: New BCC-first components and component-specific styles/logic.
  • src/components/wrapped: PrimeVue wrapped components (Bcc*) where we adapt APIs, defaults, slots, and behavior.
  • src/styles: Design-system CSS layers (theme, contexts, semantic tokens, utility classes).
  • src/index.ts: Public exports; add new components/composables here so consumers can import them.
  • docs and *.mdx: Storybook docs pages and design guidance content.
  • *.stories.ts/*.mdx (in src or docs): Demos, docs, and regression coverage for components.

Patching PrimeVue icons

Some PrimeVue icons are replaced with @bcc-code/icons-vue so the library uses BCC iconography. The patch is maintained with pnpm’s built-in patching.

1. Start or re-enter the patch

pnpm patch @primevue/icons

pnpm will print a path to a writable copy of the package (e.g. node_modules/.pnpm_patches/@primevue/icons@4.5.4).

2. Edit the icon mappings

  • Main barrel: Edit index.mjs in that folder. Each line that re-exports from @bcc-code/icons-vue defines one override, e.g.:

    export { ExpandMoreIcon as ChevronDownIcon } from '@bcc-code/icons-vue';
    
  • Per-icon files: After changing the main index.mjs, run the sync script so each icon’s own index.mjs (e.g. chevrondown/index.mjs) is updated to use the same BCC component:

    pnpm run sync:primevue-icon-patches
    

    That way both @primevue/icons and @primevue/icons/chevrondown (and other overridden icons) use the BCC icon.

3. Save the patch

From the project root (where package.json lives), run:

pnpm patch-commit <path-pnpm-printed-in-step-1>

Example, if pnpm printed ~/Projects/bcc-design/component-library/node_modules/.pnpm_patches/@primevue/icons@4.5.4:

pnpm patch-commit node_modules/.pnpm_patches/@primevue/icons@4.5.4

The patch is written to patches/@primevue__icons.patch and applied automatically on pnpm install.

License

Apache-2.0

Related Packages

@bcc-code/icons-vue

Icons used in the BCC design system, built as Vue components.

650,175 2

Version History

Version Released License
1.5.3 Apache-2.0
1.5.2 Apache-2.0
1.5.0 Apache-2.0
1.4.40 Apache-2.0
1.4.39 Apache-2.0
Pre-releases (249)
Version Released License
0.0.0-dev.892612c Apache-2.0
0.0.0-dev.1a5d955 Apache-2.0
0.0.0-dev.f41f3d5 Apache-2.0
0.0.0-dev.ac6c08f Apache-2.0
0.0.0-dev.181fcd0 Apache-2.0