Skip to content

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.

bash
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-css

Import both at your app entry point:

js
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):

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):

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:

ts
/// <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:

json
{
  "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:

bash
pnpm add @signicat/catnip-components-react @signicat/catnip-css

The 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 ​

EntryImportUse case
Default@signicat/catnip-componentsStandard ESM/UMD; use with Vue, design tokens, etc.
FOUC prevention@signicat/catnip-components/foucPrevention.min.cssHides catnip-* elements until styles load; include before component CSS
Machine API@signicat/catnip-components/custom-elements.jsonCustom Elements Manifest (tags, attributes, events, slots)
HTML editor data@signicat/catnip-components/html-custom-data.jsonVS Code / Cursor html.customData
Agent skill@signicat/catnip-components/SKILL.mdOffline copy of the agent skill

Design Tokens ​

bash
npm install @signicat/catnip-design-tokens

Usually 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 ​

bash
npm install @signicat/catnip-css

Required alongside @signicat/catnip-components for correctly styled components (see Components). Also provides typography/spacing utilities, grid, and icons CSS.

Icons ​

bash
npm install @signicat/catnip-icons

Registry ​

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:

bash
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:

js
// Shell entry — mount once
import "@signicat/catnip-components";
import "@signicat/catnip-css";
html
<!-- Remote — tags work without a second install -->
<catnip-button appearance="primary">Save</catnip-button>
tsx
// React remote — wrappers only; the shell still owns registration and CSS
import { CatnipButton } from "@signicat/catnip-components-react/wrappers";
js
// 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 ​

EnvironmentBase URL
Productionhttps://static.signicat.com/catnip/
Developmenthttps://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 segmentPackagenpm 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.

html
<!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:

html
<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:

FileOne <script>Notes
catnip-components.standalone.js✅ RecommendedIIFE; Vue + icon/illustration maps inlined
catnip-components.umd.js⚠️ PartialClassic <script defer> (not type="module"); still expects externals for some SVG maps
catnip-components.es.js❌ Incomplete aloneRegisters 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):

html
<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):

html
<link rel="stylesheet" href="https://static.signicat.com/catnip/css/latest/styles.css" />

Optional extras from the same CDN base:

NeedFile
Dark modeAlready 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 resetcss/latest/global-reset.css (load before styles.css)
Bootstrap gridcss/latest/bs-grid.css
Icon webfont onlyicons/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):

html
<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/ ​

FilePurpose
catnip-components.standalone.jsCDN-only IIFE — recommended without a bundler
catnip-components.es.jsESM build (CDN: needs import map for SVG maps; npm: use with bundler)
catnip-components.umd.jsUMD build (needs bundler or global Vue)
foucPrevention.min.cssHide catnip-* until styles load
style.cssComponent stylesheet (usually not needed with standalone)
custom-elements.jsonCustom Elements Manifest for tooling
html-custom-data.jsonVS Code / Cursor HTML custom data (html.customData)
SKILL.mdAgent skill (also at this docs host /skills/catnip/SKILL.md)

@signicat/catnip-css → css/ ​

FilePurpose
styles.cssCDN 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 / .ttfIcon font files for CDN (not in the npm tarball)
global-reset.cssOptional CSS reset
bs-grid.cssOptional Bootstrap grid

npm installs styles.npm.css (@import for design-tokens + icons; Inter via @signicat/catnip-assets).

@signicat/catnip-design-tokens → design-tokens/ ​

FilePurpose
css/default.cssLight theme CSS variables on :root
css/dark.cssDark semantic overrides (with data-theme="dark")
css/endui.cssEndUI / whitelabel overrides for data-theme="endui" on <html>
css/endui-scoped.cssEndUI plus dependent tokens, for data-theme="endui" on a wrapper
js/default.js / js/dark.js / js/endui.jsToken objects for JavaScript

@signicat/catnip-icons → icons/ ​

FilePurpose
catnip-icons.min.cssIcon webfont only (also inlined into css/…/styles.css)
catnip-icons.woff2Font file (referenced by the CSS)
svg-map.mjsLazy SVG map (inlined in standalone; external in ES build)

@signicat/catnip-assets → assets/ ​

PathPurpose
fonts/inter/…Inter variable font files
illustrations-svg.mjsLazy illustration map for catnip-graphic
country-flags-svg.mjsLazy flag SVG map
countries/index.jsCountry 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
VueBundled in standalonePeer dependency
Icon / illustration chunksInlined in standaloneLazy-loaded via bundler
TypeScriptNo types from CDNFull types from packages
ReactUse @signicat/catnip-components-react via npmRecommended 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 ​

Catnip Design System by Signicat