@feugene/granularity
@feugene/granularity
@feugene/granularity is a Vue 3 design system package that helps you build interfaces faster, cleaner, and more
predictably: with ready-made components, a transparent styling system, granular imports, and a build
pipeline that ships a machine-generated manifest instead of setup instructions.
It's built for cases where a design system needs to be more than just a set of UI pieces — a working engineering tool: convenient for a product team, scalable for a large application, and flexible enough for different adoption strategies.
Why it exists
- to launch new screens and features on a single visual foundation;
- to adopt the package incrementally, without rewriting the whole application;
- to control the size of the
JSandCSSyou ship, when that actually matters; - to use the same package both as a ready-made component library and as a source of low-level package-level APIs.
What makes granularity good
- Fast start without unnecessary magic. You can simply import components and ready-made style entrypoints.
- Granular imports. Every component is its own subpath export, so the bundle carries exactly what you import and nothing next to it.
- Sane styling. Tokens, base styles, themes, and component-level CSS are split into clear layers.
- Ready for real scale. The package works for "just plugged in a few components" as well as scenarios where dependency-aware imports, safelist, and precise CSS pipeline tuning matter.
- One plugin, no scanning. The package ships
granum.manifest.json: classes, consumed tokens, dependencies, theme files and component CSS are computed when the package is built, so the application reads them instead of scanningnode_modules. - Not just components. Alongside the UI you get directives, a file validation API, and utility entrypoints for infrastructure scenarios.
Technical highlights
- root export:
@feugene/granularity— plugins, composables, utilities, constants and types. Components come from their subpaths: withgranum, a component imported from the root is aComponentRootImportError, because the selection only sees a component by its subpath and the root loads the whole package; - component subpath exports:
@feugene/granularity/components/<ComponentName>; - ready-made CSS entrypoint:
@feugene/granularity/styles.css— theslatetheme in both modes (light,dark) with the core component tokens and the base layer in one file, for consumers who do not run the build pipeline. A mode is switched by the pairdata-theme="slate-dark". A component's own CSS is not there: withgranumit arrives through the manifest; - low-level foundation exports: a ready theme of the catalog by parts —
@feugene/granularity/themes/<theme>/root.cssplusthemes/<theme>/<mode>.cssfor the modes you need — or whole,themes/<theme>.css;@feugene/granularity/styles/base.css,@feugene/granularity/styles/preflight.css; - package-level API:
@feugene/granularity/directives,@feugene/granularity/fileValidation; - design tokens as data: the registry of component tokens at
@feugene/granularity/tokens; global tokens, theme data and the theme builder live in@feugene/granularity-tokens, a dependency of this package; - build manifest:
@feugene/granularity/granum.manifest.json— what the application'sgranum()plugin reads; it also records the utility vocabulary the classes belong to in itsengineblock. The provider registry itself stays available as@feugene/granularity/granular-providerfor packages that extend it.
Limitations
RTL is not supported. Components lay themselves out with physical directions (pl-/pr-,
ml-/mr-, left-/right-), and dir="rtl" is not read anywhere: a right-to-left document will
render mirrored padding, offsets and floating panels. This is a deliberate decision for the 1.x
line — moving to logical properties changes how every component looks, which is a visual breaking
change and belongs in a major release, not a patch. See docs/styling.md.
Quick start
yarn add @feugene/granularity vue @floating-ui/dom
@floating-ui/dom is a required peer dependency, not a bundled one: positioning (GrDropdown,
GrSelect, GrAutocomplete, GrTreeSelect, GrTooltip) is built on it, and keeping it external
means an application that already uses floating-ui ends up with a single copy.
The overlay components (GrModal, GrDrawer, GrDialog, GrImageViewer) need nothing else —
their focus trap, layer stack and scroll lock are the package's own primitives. @headlessui/vue
was dropped in 0.15.0 and is not a peer dependency; if it is still installed for this package alone,
it can be removed.
The supported setup is the granum plugin:
yarn add -D @feugene/granum @feugene/granum-engine-wind
Two packages, not one: granum is the pipeline and ships no utility engine of its own, so the
application picks the vocabulary and hands over an instance. @feugene/granum-engine-wind is the
default implementation — preset-wind3 plus the extra rule the components are drawn with.
// granum.config.ts
import { defineGranumConfig } from '@feugene/granum/vite'
import { windEngine } from '@feugene/granum-engine-wind'
export default defineGranumConfig({
engine: windEngine(),
providers: ['@feugene/granularity'],
appSources: { dirs: ['src'] },
})
The package declares the vocabulary its classes are written against —
unocss/preset-wind3+granum@66. An engine with a different dialect makes granum report
provider-dialect-mismatch and name every class it had to drop, instead of letting components
render half-styled. See docs/granum.md.
// src/main.ts
import 'virtual:granum.css'
That single module carries five cascade layers: tokens, base, themes, the CSS of the components you selected, and the utility classes they are built from.
Components are imported from their subpaths:
<script setup lang="ts">
import { GrButton } from '@feugene/granularity/components/GrButton'
</script>
<template>
<GrButton>Save</GrButton>
</template>
Without the plugin there is still a static fallback — @feugene/granularity/styles.css — with tokens,
the base layer, the preflight and the built-in light/dark themes. What it does not carry is the
utility classes, so components render with their own CSS but without layout.
Granular imports, in numbers
| What you import | gzip | of the barrel |
|---|---|---|
| the whole package from the root | 665.9 kB | 100 % |
the lightest component — GrSkeleton |
1.7 kB | < 1 % |
the median component — GrSegmented |
21.5 kB | 3 % |
| the 5 heaviest together | 261.3 kB | 39 % |
These numbers do not add up: shared code is counted again in every row but paid for once, which is why
the set is shown as a union rather than a sum. They are an upper bound — the gzip of everything a subpath
pulls out of dist, before the application bundler shakes it further and minifies it again.
The weight of every component — docs/entry-sizes.md.
The rest of the family
The core ships the general-purpose components. Anything that carries a heavy dependency, belongs to a
domain of its own, or is needed by a minority of consumers lives in a companion package with a peer
on this one — the core stays lean, and you install only what you reach for.
| Package | Version | What it adds |
|---|---|---|
@feugene/granularity-charts |
2.0.2 | Charts — own SVG, zero dependencies, drawn with theme tokens. |
@feugene/granularity-chrono |
2.0.2 | Calendar, date and time components — no third-party date widget, no date library. |
@feugene/granularity-code |
2.0.2 | Code surfaces: view, edit and diff — the viewer and the diff carry no dependencies at all. |
@feugene/granularity-dashboard |
2.0.2 | Widget grid — drag, resize, breakpoints and layout persistence, zero dependencies. |
@feugene/granularity-datasource |
0.1.2 | List state: sorting, filters, paging, URL sync and race-free fetching behind one composable. |
@feugene/granularity-devtools |
2.1.1 | Vue DevTools panel — where a prop value came from, the overlay layer stack and design-system warnings. |
@feugene/granularity-editor |
2.0.2 | Rich-text editing: a TipTap-backed GrRichText field with a design-system toolbar. |
@feugene/granularity-forms-schema |
2.0.2 | Schema-driven forms — zod and JSON Schema into real form fields, zero dependencies. |
@feugene/granularity-media |
2.0.2 | Media components: image cropping, camera capture, code scanning and video playback. |
@feugene/granularity-test-kit |
2.2.0 | Test gates for @feugene/granularity design-system packages — token, registry and defaults contracts as reusable factories. |
@feugene/granularity-tokens |
2.1.0 | Design tokens and themes of @feugene/granularity: the token registry, theme data by mode and the theme builder. |
@feugene/unplugin-granularity |
1.2.1 | unplugin-vue-components resolver — granular auto-import for components and directives. |
Documentation
docs/README.md— overview and documentation mapdocs/installation.md— installation, public entrypoints, and adoption strategiesdocs/styling.md— style layers, themes, and import orderdocs/tokens.md— component token reference (generated from each component'stokens.json); global tokens and themes —@feugene/granularity-tokensdocs/entry-sizes.md— the weight of every component as a subpath (generated from the build)docs/modes.md— modes in the app: switching, islands, SSR, your own modes in the configthemes.mdof@feugene/granularity-tokens— themes: roles, contrast rules, building your own mode or themedocs/keyboard.md— keyboard contract per componentdocs/overlays.md— overlay contract: portal, layer stack, Esc,inert, focusdocs/z-index.md— layering scaledocs/ssr.md— server-side rendering contractdocs/granum.md—granumintegrationdocs/localization.md— how the package plugs into application localizationdocs/directives.md— package-level directivesdocs/file-validation.md— file validation APIdocs/components.md— catalog of published componentsdocs/ADDING_COMPONENTS.md— internal guide for adding a new component
Related Packages
Vue 3 flavour of the Cubo UI kit — components built on @cuboapp/styles design to...
A set of ready-to-use UI components for Vue 3, styled according to the Flowbite...
Version History
| Version | Released | License |
|---|---|---|
| 3.1.0 | LicenseRef-Granularity-EUC-1.1 | |
| 3.0.0 | LicenseRef-Granularity-EUC-1.1 | |
| 2.4.0 | LicenseRef-Granularity-EUC-1.1 | |
| 2.3.0 | LicenseRef-Granularity-EUC-1.1 | |
| 2.2.0 | LicenseRef-Granularity-EUC-1.1 | |
| 2.1.0 | LicenseRef-Granularity-EUC-1.1 | |
| 2.0.0 | LicenseRef-Granularity-EUC-1.1 | |
| 1.1.1 | LicenseRef-Granularity-EUC-1.1 | |
| 1.1.0 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.21 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.20 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.19 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.18 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.17 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.16 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.15 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.14 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.13 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.12 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.11 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.10 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.9 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.8 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.7 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.6 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.5 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.4 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.3 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.2 | LicenseRef-Granularity-EUC-1.1 | |
| 1.0.1 | LicenseRef-Granularity-EUC-1.1 |
Showing the latest 30 of 105. See every release on npm