Getting started
Five steps from an empty directory to a coloured button on screen. Everything deeper lives on the neighbouring pages.
Machine-translated, not yet reviewed. Read the original
The shortest useful page on this site. No options, no caveats, no “but what if you are on Nuxt” — one path that gets you to a working component. The branches start on installation and in configuration.
What you need
- Node 22 or newer. Below that the package does not install: it is ESM-only and says so in
engines. "type": "module"in the application’spackage.json. CommonJS is not supported.- Vue 3.5 or newer and a Vite build. Other bundlers are not forbidden, but they are not verified either.
Install
npm i @feugene/granularity vue @floating-ui/dom @unocss/resetpnpm add @feugene/granularity vue @floating-ui/dom @unocss/resetyarn add @feugene/granularity vue @floating-ui/dom @unocss/resetbun add @feugene/granularity vue @floating-ui/dom @unocss/resetAnd the part that only runs at build time and never reaches the bundle:
yarn add -D unocss @feugene/unocss-preset-granular @unocss/preset-mini@floating-ui/dom is a required peer dependency, not a recommendation. It is
what positions GrSelect, GrDropdown, GrAutocomplete, GrTreeSelect,
GrTooltip and GrPopover. Without it the application throws on the first
import of a dropdown. The modal layer, by contrast, needs nothing: the focus
trap, inert and the Esc order are the package’s own primitives.
Configuration
The design system’s CSS is not imported as files — UnoCSS assembles it from the
granular provider, and the provider reads the package’s built dist. So there is
exactly one source of truth:
import { defineConfig, presetMini } from 'unocss'
import { granularContent, presetGranularNode } from '@feugene/unocss-preset-granular/node'
import granularityProvider from '@feugene/granularity/granular-provider/node'
// One object for both calls. Let them drift apart and components arrive unstyled.
const granular = {
providers: [granularityProvider],
components: [{ provider: '@feugene/granularity', names: ['GrButton'] }],
themes: { names: ['light', 'dark'] },
layer: 'granular' as const,
}
export default defineConfig({
// `@unocss/vite` reads `content` from the top level of the config only,
// not from the preset. Skip it and the extractor never looks into `dist`.
content: granularContent(granular),
presets: [presetMini(), presetGranularNode(granular)],
})components can be left out entirely — then every component of the provider
lands in the CSS. Listing them narrows the sheet down to the set you need, and
this is the one place where you pay for granularity with attention.
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import UnoCSS from 'unocss/vite'
export default defineConfig({ plugins: [Vue(), UnoCSS()] })Three imports, and the order between them matters
import '@unocss/reset/tailwind-compat.css'
import 'virtual:uno:granular.css'
import 'virtual:uno.css'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')There are two virtual modules and both are required. The granular layer holds
the foundation — :root { --gr-* }, the base layer, the themes, per-component
variables. The utility classes the component templates are drawn with are
generated into the shared virtual:uno.css. Forget the second import and you get
components with tokens but without layout: the colours are there, the geometry is
not.
Without layer: 'granular' there is no separate layer module and everything
arrives in a single virtual:uno.css — that is correct too. The layer is for
when the order relative to your own CSS matters.
The first component
<script setup lang="ts">
import { GrButton } from '@feugene/granularity/components/GrButton'
</script>
<template>
<GrButton tone="primary">Save</GrButton>
</template>Importing from a subpath rather than from the package root is granularity itself. It pulls one component and its graph, not a barrel.
Run vite. The button should be coloured, with a shadow and a focus ring on Tab.
If it is grey or bare, it is almost certainly one of the three CSS imports; that
exact case is worked through on the
troubleshooting page.
Next
- Installation — why the dependency list looks like this, icons, optional integrations.
- Configuration — defaults, locale, overrides at the application level.
- Theming — rebranding without touching components.
- Component catalogue — what there is at all.