Installation
Catnip ships on Signicat’s internal GitLab npm registry and on Signicat’s CDN.
- npm — For Signicat developers and CI with registry access. Use with a bundler (Vue, React, Vite, webpack). Packages are scoped
@signicat/catnip-*. - CDN — For anyone with a browser: plain HTML, server-rendered apps, or teams without npm registry access. Production: static.signicat.com/catnip/. Development: static.signicat.dev/catnip/.
Packages are not on the public npm registry today. If you cannot configure the GitLab registry and authenticate, use the CDN — not npm install.
npm
Packages are on Signicat’s GitLab registry — configure @signicat before the first install. See Registry.
Components
Install @signicat/catnip-components together with @signicat/catnip-css. Components inject their own shadow DOM styles, but they read --catnip-* design tokens (colors, typography, spacing, and so on) from the page. @signicat/catnip-css supplies those variables plus base styles and utilities — without it, components register but will not look correct.
npm install @signicat/catnip-components @signicat/catnip-css
# or
pnpm add @signicat/catnip-components @signicat/catnip-css
# or
yarn add @signicat/catnip-components @signicat/catnip-cssImport both at your app entry point:
import "@signicat/catnip-components";
import "@signicat/catnip-css";Peer dependencies: vue (when using Vue).
Vue compiler
Tell Vue that catnip-* tags are custom elements. Without this, the compiler treats them as Vue components (Failed to resolve component: catnip-button).
Vite (vite.config.ts):
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith("catnip-")
}
}
})
]
});Nuxt (nuxt.config.ts):
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith("catnip-")
}
}
});Then bind reactive / non-literal values with the leading-dot shorthand (.modelValue, .disabled). See Component API — Vue 3 and Quickstart.
TypeScript
Importing @signicat/catnip-components registers the tags and types window.Catnip. Add this to an env.d.ts (or equivalent) in the app:
/// <reference types="@signicat/catnip-components" />Vue template types still come from isCustomElement above — Catnip hosts are native custom elements, not Vue SFCs. For React, use @signicat/catnip-components-react: generated wrappers include prop and event types.
Editor autocomplete
The package ships a VS Code HTML custom data file generated from the Custom Elements Manifest. Point the editor at it so catnip-* tags and kebab-case attributes complete in HTML / Vue templates:
{
"html.customData": ["./node_modules/@signicat/catnip-components/dist/html-custom-data.json"]
}The same file is published on this docs host as /html-custom-data.json (and the manifest as /custom-elements.json). After install you can also import @signicat/catnip-components/html-custom-data.json and @signicat/catnip-components/custom-elements.json.
React
For a normal React application, install the wrapper and CSS packages:
pnpm add @signicat/catnip-components-react @signicat/catnip-cssThe default React entry depends on @signicat/catnip-components, starts custom-element registration only in the browser, and is safe to import during SSR. A child micro-frontend whose shell already owns Catnip must import @signicat/catnip-components-react/wrappers instead; that entry does not register another component runtime. See the complete React guide.
Package entry points
| Entry | Import | Use case |
|---|---|---|
| Default | @signicat/catnip-components | Standard ESM/UMD; use with Vue, design tokens, etc. |
| FOUC prevention | @signicat/catnip-components/foucPrevention.min.css | Hides catnip-* elements until styles load; include before component CSS |
| Machine API | @signicat/catnip-components/custom-elements.json | Custom Elements Manifest (tags, attributes, events, slots) |
| HTML editor data | @signicat/catnip-components/html-custom-data.json | VS Code / Cursor html.customData |
| Agent skill | @signicat/catnip-components/SKILL.md | Offline copy of the agent skill |
Design Tokens
npm install @signicat/catnip-design-tokensUsually not needed separately if you already import @signicat/catnip-css — that package bundles design tokens. Install tokens on their own only when you want the CSS or JS token files without the full Catnip CSS bundle.
CSS Utilities
npm install @signicat/catnip-cssRequired alongside @signicat/catnip-components for correctly styled components (see Components). Also provides typography/spacing utilities, grid, and icons CSS.
Icons
npm install @signicat/catnip-iconsRegistry
Catnip packages are published to the Signicat GitLab npm registry only — they are not on npmjs.com or otherwise publicly installable without Signicat credentials.
Inside Signicat (apps, CI, developers with access), configure npm and authenticate:
npm config set @signicat:registry https://gitlab.com/api/v4/projects/75004529/packages/npm/For authenticated access, use a GitLab personal access token or CI_JOB_TOKEN in CI.
Outside Signicat (or without registry access), you cannot run npm install @signicat/catnip-*. Use the CDN instead — every release mirrors dist/ to static.signicat.com/catnip/ (and static.signicat.dev/catnip/ for dev).
Public npm planned
Publishing to the public npm registry is planned for the future. When that happens, external teams may also use npm install; until then, CDN is the supported path without GitLab access.
One instance (micro-frontends)
catnip-* tags register once per document on window.customElements. The first import that runs registration wins; a second copy does not give you a second library. @signicat/catnip-css is the same: tokens and utilities belong on the host document.
This applies to npm and CDN.
Shell / root app — install and import @signicat/catnip-components and @signicat/catnip-css at the application entry (or load the CDN standalone script and CSS once). That mount also publishes JS APIs on window.Catnip (first write wins).
Child micro-frontends — do not import another component runtime or global CSS. The elements are already defined. Use <catnip-button> directly, or React children can import @signicat/catnip-components-react/wrappers for adapters that do not register components. For i18n, config, and helpers, call the host instance — do not import @signicat/catnip-components:
// Shell entry — mount once
import "@signicat/catnip-components";
import "@signicat/catnip-css";<!-- Remote — tags work without a second install -->
<catnip-button appearance="primary">Save</catnip-button>// React remote — wrappers only; the shell still owns registration and CSS
import { CatnipButton } from "@signicat/catnip-components-react/wrappers";// Remote — same window as the shell (after the shell has mounted Catnip)
window.Catnip.version; // e.g. "1.0.0" — the shell’s mounted library
window.Catnip.registerTranslate((key) => i18n.global.t(key));
window.Catnip.configure({ automaticTypeConversion: true });
const value = window.Catnip.parseEmitDetail(event);A second bundled copy skips re-defining tags, but its registerTranslate / CatnipConfig are a dead copy and will not affect the mounted components. See Configuration.
Versioning
The shell owns the Catnip version. When the root upgrades @signicat/catnip-components / @signicat/catnip-css (or the CDN URL), every remote on that document runs that version. There is no per-MFE component version. Remotes can read window.Catnip.version to see which @signicat/catnip-components build the shell mounted.
Remotes must stay API-compliant with the shell’s version: markup, props, events, slots, and window.Catnip calls have to match what the shell actually mounted.
Bug fixes and patches are the easy path: one shell bump ships the fix to all remotes at once. Prefer that over forked copies in child apps.
Breaking changes are costly in this model. A breaking Catnip release cannot land in the shell until all consuming remotes have been updated. Library authors should treat breaking API changes as last resort; consumers should plan coordinated upgrades across the shell and remotes, not independent version pins.
CDN
Every @signicat/catnip-* package is mirrored to the CDN on each release. Load stylesheets with <link> tags. For components without a bundler, use the standalone IIFE (one script tag). The ES build is also on the CDN for advanced setups with an import map.
CDN hosts and URL pattern
| Environment | Base URL |
|---|---|
| Production | https://static.signicat.com/catnip/ |
| Development | https://static.signicat.dev/catnip/ |
Each package is deployed under its monorepo folder name:
{base}{package}/{version}/{file}
{base}{package}/latest/{file}Examples (production):
https://static.signicat.com/catnip/components/latest/catnip-components.standalone.js
https://static.signicat.com/catnip/css/0.0.13/styles.css
https://static.signicat.com/catnip/icons/latest/catnip-icons.min.css| Path segment | Package | npm name |
|---|---|---|
components/ | Web Components | @signicat/catnip-components |
components-react/ | React wrappers | @signicat/catnip-components-react |
css/ | Base styles and utilities | @signicat/catnip-css |
design-tokens/ | CSS variables and JS tokens | @signicat/catnip-design-tokens |
icons/ | Icon webfont and SVG map | @signicat/catnip-icons |
assets/ | Fonts, illustrations, flags, logos | @signicat/catnip-assets |
Versioned vs latest
{package}/{version}/— immutable for that release. Prefer this in production so upgrades are explicit.{package}/latest/— always points at the newest release. Convenient for prototypes; pin a version when you ship.
Components
The standalone IIFE bundles Vue, all catnip-* custom elements, and lazy-loaded icon/illustration SVG maps. You do not need npm, a bundler, a separate Vue import, or an import map.
catnip-components.standalone.js is not on npm (it is built in CI and deployed to the CDN only). The ES/UMD builds on npm expect a bundler.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Design tokens + icon webfont + Inter + utilities (required for styled components) -->
<link rel="stylesheet" href="https://static.signicat.com/catnip/css/latest/styles.css" />
<!-- Optional: hide catnip-* tags until component styles are injected -->
<link rel="stylesheet" href="https://static.signicat.com/catnip/components/latest/foucPrevention.min.css" />
</head>
<body>
<catnip-button appearance="primary">Save</catnip-button>
<catnip-icon name="tick" size="32"></catnip-icon>
<script src="https://static.signicat.com/catnip/components/latest/catnip-components.standalone.js" defer></script>
</body>
</html>Script tag, not module
The standalone build is an IIFE assigned to the global CatnipComponents. Use a classic <script src="…" defer> — not type="module".
The standalone script injects component styles (layout, states, and so on). You still need @signicat/catnip-css on the page (via the <link> tags above) so --catnip-* tokens resolve — see CSS, tokens, and icons — CDN.
Versioned URLs (EndUI-style)
Pin a release the same way EndUI did with version in the path:
<script src="https://static.signicat.dev/catnip/components/0.0.31/catnip-components.standalone.js" defer></script>Use latest/ only for prototypes; ship with {version}/ in production.
Why not catnip-components.umd.js with one script tag?
Catnip also publishes catnip-components.es.js and catnip-components.umd.js on the CDN (same files as npm). A single script tag like EndUI’s endui-components.umd.js is not equivalent today:
| File | One <script> | Notes |
|---|---|---|
catnip-components.standalone.js | ✅ Recommended | IIFE; Vue + icon/illustration maps inlined |
catnip-components.umd.js | ⚠️ Partial | Classic <script defer> (not type="module"); still expects externals for some SVG maps |
catnip-components.es.js | ❌ Incomplete alone | Registers many components, but catnip-icon / catnip-graphic need an import map |
EndUI’s bundle was self-contained under one URL. Catnip’s standalone build is the same idea; umd.js / es.js are the slimmer npm-oriented builds.
Advanced: ES module + import map
If you prefer catnip-components.es.js, map lazy SVG entry points with an import map (Vue is already bundled in the ES file):
<script type="importmap">
{
"imports": {
"@signicat/catnip-icons/svg": "https://static.signicat.com/catnip/icons/latest/svg-map.mjs",
"@signicat/catnip-assets/illustrations/svg": "https://static.signicat.com/catnip/assets/latest/illustrations-svg.mjs",
"@signicat/catnip-assets/countries": "https://static.signicat.com/catnip/assets/latest/countries/index.js",
"@signicat/catnip-assets/countries/flags/svg": "https://static.signicat.com/catnip/assets/latest/country-flags-svg.mjs"
}
}
</script>
<script type="module" src="https://static.signicat.com/catnip/components/latest/catnip-components.es.js"></script>Pin versioned CDN URLs in production. Without the import map, catnip-icon and catnip-graphic fail at runtime when they load SVG chunks.
CSS, tokens, and icons
Required with components — load @signicat/catnip-css so --catnip-* tokens, the icon webfont, Inter, and utilities are on the page. Components read these variables; the standalone script does not replace this CSS.
On CDN, styles.css is self-contained (tokens, icons, Inter with ./fonts/inter/… next to the file):
<link rel="stylesheet" href="https://static.signicat.com/catnip/css/latest/styles.css" />Optional extras from the same CDN base:
| Need | File |
|---|---|
| Dark mode | Already in styles.css — set data-theme="dark" on <html> — see Theming — CDN |
| EndUI (whitelabel) | design-tokens/latest/css/endui.css on <html>, or endui-scoped.css on a wrapper, plus data-theme="endui" — see Theming — EndUI |
| Global reset | css/latest/global-reset.css (load before styles.css) |
| Bootstrap grid | css/latest/bs-grid.css |
| Icon webfont only | icons/latest/catnip-icons.min.css (when you are not loading styles.css) |
See also CSS overview — CDN for how this maps to optional modules.
Assets and fonts
CDN css/latest/styles.css already loads Inter from css/latest/fonts/inter/. You do not need a separate @font-face block for the default Catnip typeface on CDN.
For npm, @signicat/catnip-css references Inter through @signicat/catnip-assets (a dependency); your bundler resolves the font files — no manual @font-face unless you opt out of the CSS package faces.
Illustrations, flags, and pictograms are under assets/latest/… — see Assets overview — CDN.
Configuration
After the standalone script loads, JS APIs are on window.Catnip (same object the shell mounted). Prefer that in micro-frontends. The IIFE also exposes named exports on CatnipComponents (an alias, not a second instance):
<script src="https://static.signicat.com/catnip/components/latest/catnip-components.standalone.js" defer></script>
<script>
window.Catnip.configure({
automaticTypeConversion: true,
nativeFormBehaviour: true
});
window.Catnip.registerTranslate((key) => myTranslations[key] ?? key);
</script>With the ES build and import map, a shell may import { CatnipConfig } in a module script — remotes should still use window.Catnip. See Configuration.
Package file reference
@signicat/catnip-components → components/
| File | Purpose |
|---|---|
catnip-components.standalone.js | CDN-only IIFE — recommended without a bundler |
catnip-components.es.js | ESM build (CDN: needs import map for SVG maps; npm: use with bundler) |
catnip-components.umd.js | UMD build (needs bundler or global Vue) |
foucPrevention.min.css | Hide catnip-* until styles load |
style.css | Component stylesheet (usually not needed with standalone) |
custom-elements.json | Custom Elements Manifest for tooling |
html-custom-data.json | VS Code / Cursor HTML custom data (html.customData) |
SKILL.md | Agent skill (also at this docs host /skills/catnip/SKILL.md) |
@signicat/catnip-css → css/
| File | Purpose |
|---|---|
styles.css | CDN main bundle (inlined tokens + icons, Inter via ./fonts/inter/…) |
fonts/inter/… | Inter files for CDN styles.css (not in the npm tarball) |
catnip-icons.woff2 / .woff / .ttf | Icon font files for CDN (not in the npm tarball) |
global-reset.css | Optional CSS reset |
bs-grid.css | Optional Bootstrap grid |
npm installs styles.npm.css (@import for design-tokens + icons; Inter via @signicat/catnip-assets).
@signicat/catnip-design-tokens → design-tokens/
| File | Purpose |
|---|---|
css/default.css | Light theme CSS variables on :root |
css/dark.css | Dark semantic overrides (with data-theme="dark") |
css/endui.css | EndUI / whitelabel overrides for data-theme="endui" on <html> |
css/endui-scoped.css | EndUI plus dependent tokens, for data-theme="endui" on a wrapper |
js/default.js / js/dark.js / js/endui.js | Token objects for JavaScript |
@signicat/catnip-icons → icons/
| File | Purpose |
|---|---|
catnip-icons.min.css | Icon webfont only (also inlined into css/…/styles.css) |
catnip-icons.woff2 | Font file (referenced by the CSS) |
svg-map.mjs | Lazy SVG map (inlined in standalone; external in ES build) |
@signicat/catnip-assets → assets/
| Path | Purpose |
|---|---|
fonts/inter/… | Inter variable font files |
illustrations-svg.mjs | Lazy illustration map for catnip-graphic |
country-flags-svg.mjs | Lazy flag SVG map |
countries/index.js | Country metadata (name, code, dial_code, …) |
illustrations/… | Static SVG files |
countries/flags/… | Country flag SVGs |
CDN vs npm
| CDN (standalone) | npm + bundler | |
|---|---|---|
| Setup | <script defer> + optional <link> | npm install + import |
| Vue | Bundled in standalone | Peer dependency |
| Icon / illustration chunks | Inlined in standalone | Lazy-loaded via bundler |
| TypeScript | No types from CDN | Full types from packages |
| React | Use @signicat/catnip-components-react via npm | Recommended path |
Self-hosting
CI builds catnip-components.standalone.js with pnpm run build:standalone (after pnpm build) and uploads every package’s dist/ to GCS. You can copy dist/ from a release and serve it from your own static bucket — keep the same relative paths if you mirror multiple packages (so icon font URLs in catnip-icons.min.css keep working).
Next Steps
- Quickstart — Use your first component
- Agent skill — Point a coding agent at Catnip
- Theming — Add light/dark themes
- Components — Explore all components