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 they are registered; 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 |
Icons and graphics loading
catnip-icon and catnip-graphic download each SVG the first time its name is used, then reuse it for every element on the page. To skip that first request for SVGs visible on first load, preload them at startup:
import { preloadIcons, preloadGraphics } from "@signicat/catnip-components";
preloadIcons(["home", "settings"]);
preloadGraphics(["hero/onboarding"]);Micro-frontend remotes call window.Catnip.preloadIcons / window.Catnip.preloadGraphics instead.
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 the components are registered -->
<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"); expects the SVG loader modules as globals (CatnipIconsSvg, CatnipAssetsIllustrations, CatnipAssetsCountryFlags) |
catnip-components.es.js | ❌ Incomplete alone | Imports the SVG loader modules by bare specifier, so it needs an import map to load |
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 the ES file fails to load, because it imports these loader modules directly.
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"></script>
<script>
window.Catnip.configure({
automaticTypeConversion: true,
nativeFormBehaviour: true
});
window.Catnip.registerTranslate((key) => myTranslations[key] ?? key);
</script>The script is not deferred here so window.Catnip exists when the inline script runs; an inline script placed after a defer script runs before it.
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 they are registered |
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