Installation
Two commands.
Set up once, then add the components you want. Their source is copied into your project; nothing is imported from node_modules.
You need a Vue 3.5, Nuxt 4 or Astro project and Node 18 or later. The browsers need to be from 2024 onward, because the CSS uses light-dark(), @layer, color-mix() and oklch().
1. Set up
Run this in your project's folder. It detects the framework, suggests folders, writes ermine.json and copies the theme stylesheet. Add -y to accept the suggested folders without being asked.
npx ermineui initpnpm dlx ermineui inityarn dlx ermineui initbunx ermineui init{
"components": "src/components/ui",
"lib": "src/lib/ermine",
"styles": "src/styles/ermine.css"
}2. Add components
Name as many as you like. Each brings the helpers and other components it depends on. Files that already exist are kept unless you pass --overwrite.
npx ermineui add button dialog select
npx ermineui add dashboardpnpm dlx ermineui add button dialog select
pnpm dlx ermineui add dashboardyarn dlx ermineui add button dialog select
yarn dlx ermineui add dashboardbunx ermineui add button dialog select
bunx ermineui add dashboardThe second line adds a block: a section of a page, already put together, along with every component it uses. Blocks go in a blocks folder beside your components. Browse all 143 components and 14 blocks.
3. Load the stylesheet and use them
Vue with Vite
// src/main.ts
import './styles/ermine.css'<script setup lang="ts">
import { Button } from '@/components/ui/button'
</script>
<template>
<Button variant="outline">Save</Button>
</template>Nuxt
// nuxt.config.ts
export default defineNuxtConfig({
css: ['~/assets/css/ermine.css'],
components: [
// Auto-import the components by their own names: <Button>, <DialogContent>, ...
{ path: '~/components/ui', pathPrefix: false, extensions: ['.vue'] },
// The same for blocks, if you add any: <Dashboard>, <SignIn>, ...
{ path: '~/components/blocks', pathPrefix: false, extensions: ['.vue'] },
'~/components',
],
})Components are then available in templates without imports. toast is a function, so import it: import { toast } from '~/components/ui/toast'.
Astro
Add the Vue integration with npx astro add vue, import the stylesheet in a layout, and use the components inside a Vue island.
---
import '../styles/ermine.css'
import SettingsForm from '../components/SettingsForm.vue'
---
<SettingsForm client:load />Compound components such as dialog, select and tabs share state between their parts, so compose them inside one .vue file and not across separate islands. Static ones such as Button, Badge and Card can be used directly in .astro files with no client directive.
Commands
| Command | What it does |
|---|---|
ermine init | Create ermine.json and the theme stylesheet. -y accepts the suggested folders. |
ermine add <name...> | Copy components or blocks and what they depend on. --all copies every component. |
ermine list | Show what is available and which you already have. |
--overwrite | Replace files that already exist. |
--cwd <dir> | Run as if started in another folder. |
--registry <url or path> | Read components from a different registry.json, such as your own fork. |
Theming
ermine.css defines every colour, radius, shadow and duration as a CSS variable. Edit the values and every component follows. The file is yours and is never overwritten, even with --overwrite.
:root {
--er-primary: light-dark(oklch(0.5 0.2 265), oklch(0.75 0.15 265));
--er-radius: 0.375rem;
}Or start from a ready-made colour theme: a base for the greys and an accent for the primary colour, each checked for contrast in light and dark.
npx ermineui theme slate bluepnpm dlx ermineui theme slate blueyarn dlx ermineui theme slate bluebunx ermineui theme slate blue- Dark mode follows the operating system. To force a theme, put
class="dark"orclass="light"on<html>, or on any element to theme only what is inside it. - Overriding a component. Component styles sit in
@layer components, so any rule you write outside a layer wins without!important. Or edit the component's own<style>block; it is your code. - With Tailwind. The layer has the same name Tailwind uses, so utility classes on an Ermine component override its defaults.
.er-button[data-variant='outline'] { border-style: dashed; }With an AI assistant
Claude, Codex, Cursor and other assistants can do all of this for you over the Model Context Protocol, from your editor or from claude.ai. See connecting an assistant.
Installing by hand
The command line is a convenience. Every component page shows the source of each file and where it goes, so you can create them yourself.