@commonpub/ui

Headless Vue 3 components with CSS custom property theming for CommonPub
10,748 6
Install
npm install @commonpub/ui
Latest Version:0.16.1
Vue:3
License:AGPL-3.0-or-later
Last Updated:Oct 20, 2026
Links: GitHub  ·  npm
Maintainer: virgilvox

@commonpub/ui

Headless Vue 3 component library with CSS custom property theming.

Overview

Accessible, headless UI components built with Vue 3 Composition API (<script setup lang="ts">). Components define structure and behavior only. All visual styling is controlled via CSS custom properties (var(--*)). Zero hardcoded colors or fonts.

Includes 7 built-in themes (12 theme CSS files) and a theming API for runtime theme switching with inline token overrides.

Installation

pnpm add @commonpub/ui

Components

Component Description Key Features
Button Interactive button with variants Loading state, disabled, keyboard
IconButton Icon-only button with tooltip ARIA label required
Input Text input with label and error Validation feedback
Textarea Multi-line text input Auto-resize option
Select Dropdown select Keyboard navigable
Tooltip Hover/focus tooltip Accessible, auto-positioned
Popover Floating content panel Click-outside dismiss, focus trap
Menu Dropdown menu trigger Keyboard nav, roving tabindex
MenuItem Menu item Active/disabled states
Dialog Modal dialog Focus trap, Escape to close
Tabs Tabbed interface ARIA tablist, keyboard arrows
Badge Status/count badge Variants: default, success, warning
Avatar User avatar Image with initials fallback
Stack Flex layout container Direction, gap, alignment
Separator Visual divider Horizontal/vertical, ARIA separator
Card Content card container Header, body, footer slots
Toggle Toggle switch On/off state, ARIA switch
TagInput Tag input with chips Add/remove tags, keyboard support
ProgressBar Progress indicator Percentage, label, ARIA progressbar
Alert Alert/banner message Variants: info, success, warning, error
Toolbar Toolbar container Horizontal/vertical, ARIA toolbar
VisuallyHidden Screen reader-only text Accessibility utility

Usage

<script setup lang="ts">
import { Button, Input, Dialog, Tabs } from '@commonpub/ui';

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

<template>
  <Button @click="handleClick" variant="primary">
    Save Project
  </Button>

  <Input
    v-model="name"
    label="Project Name"
    :error="nameError"
  />

  <Dialog v-model:open="showModal" title="Confirm Delete">
    <p>Are you sure you want to delete this project?</p>
  </Dialog>
</template>

All components accept a class prop for external styling:

<Button class="my-custom-button">Click me</Button>

Theming

Built-in Themes

7 built-in themes (BUILT_IN_THEMES):

Theme ID Description
Classic Light base Sharp corners, offset shadows, blue accent — the CommonPub signature
Classic Dark dark Dark surfaces with the same offset shadow aesthetic
Generics generics Dark minimal theme with blue accent and soft glow
Agora Light agora Warm parchment backgrounds, green accent, serif display font
Agora Dark agora-dark Grove-tinted darks with green accent, serif display font
Stoa Light stoa Warm paper, moss accent, serif display + reading fonts, soft rounded geometry
Stoa Dark stoa-dark Warm near-black with brighter moss accent, the same bookish serif geometry

Stoa is the current CommonPub default (the server-side fallback resolves to stoa/stoa-dark). Consumer apps (e.g., deveco.io) add their own theme CSS overrides on top of these.

Importing Theme CSS

// Import the themes you want (the layer bundles all of them automatically)
import '@commonpub/ui/theme/base.css';
import '@commonpub/ui/theme/dark.css';
import '@commonpub/ui/theme/stoa.css';
import '@commonpub/ui/theme/stoa-dark.css';

Runtime Theme Switching

import { applyThemeToElement, getThemeFromElement, isValidThemeId } from '@commonpub/ui';

// Apply theme via data-theme attribute
applyThemeToElement(document.documentElement, 'dark');

// Apply with custom token overrides
applyThemeToElement(document.documentElement, 'base', {
  'color-primary': '#ff6600',
  'font-heading': '"Custom Font", sans-serif',
});

// Read current theme
const { themeId, overrides } = getThemeFromElement(document.documentElement);

Token Contract

The full token surface is defined in theme/base.css. All tokens are CSS custom properties:

  • Surface colors: --color-surface, --color-surface-alt, --color-surface-raised
  • Text colors: --color-text, --color-text-secondary, --color-text-muted
  • Brand colors: --color-primary, --color-accent (with hover and text variants)
  • Semantic colors: --color-success, --color-warning, --color-error, --color-info
  • Typography: --font-heading, --font-body, --font-mono, sizes, weights, line heights
  • Spacing: --space-1 through --space-24
  • Borders: Widths, radii (--radius-sm through --radius-full)
  • Shadows: --shadow-sm through --shadow-xl
  • Z-index: --z-dropdown, --z-modal, --z-toast, --z-tooltip
  • Layout: --nav-height, --sidebar-width, --content-max-width

Validating Token Overrides

import { validateTokenOverrides, TOKEN_NAMES } from '@commonpub/ui';

const { valid, invalid } = validateTokenOverrides({
  'color-primary': '#ff0000',   // valid
  'not-a-token': 'value',       // invalid
});

Accessibility

All components meet WCAG 2.1 AA:

  • Keyboard navigable (Tab, Enter, Space, Escape, Arrow keys)
  • ARIA attributes on all interactive elements
  • Focus indicators with --focus-ring token
  • prefers-reduced-motion respected
  • All components tested with axe-core

Component Standards

  • Headless: Structure and behavior only, no visual opinions
  • class prop: Every component accepts class for external styling
  • Vue 3 Composition API: <script setup lang="ts"> syntax
  • Events: Use Vue emit pattern

Development

pnpm build        # Build with vite-plugin-vue
pnpm test         # Run tests (including axe-core a11y)
pnpm typecheck    # Type-check with vue-tsc

Dependencies

  • vue (peer): Vue 3.4+

Related Packages

@soldy-ui/vue

Адаптер Vue: компоненты на headless-моделях ядра

165 1
@affino/tooltip-vue

Vue adapter for @affino/tooltip-core

772 0
op-headless-lib

op-headless-lib is a Vue 3 library that provides a suite of pre-built components...

1,831
@monolithrobotics/isoline

Headless, unstyled Vue 3 UI primitives. Behaviour and accessibility only — you b...

1,003 0
@elvora/vue

Elvora UI components for Vue 3 — same headless API as the React adapter, idiomat...

745

Version History

Version Released Vue License
0.16.1 ^3.4.0 AGPL-3.0-or-later
0.16.0 ^3.4.0 AGPL-3.0-or-later
0.15.0 ^3.4.0 AGPL-3.0-or-later
0.14.2 ^3.4.0 AGPL-3.0-or-later
0.14.1 ^3.4.0 AGPL-3.0-or-later