Installation
Published on npm as @nqmcreative/ui. Everything below
is verified against a fresh SvelteKit project on Windows.
The fast path
Four commands from nothing to a running app:
bunx sv create myapp --template minimal --types ts --install bun
cd myapp
bun add -d tailwindcss @tailwindcss/vite
bun add @nqmcreative/uiThen let the CLI do the wiring — it writes app.css, patches app.html, and adds the CSS import
to your root layout:
bunx nqm-ui initIt will not rewrite your Vite config — it prints the two lines to paste. Every write is
idempotent, so running it twice changes nothing. Add --dry-run to see what it would touch.
Or by hand
1. Install
bun add @nqmcreative/ui2. The Tailwind plugin
import tailwindcss from '@tailwindcss/vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
// tailwindcss() must come before sveltekit()
plugins: [tailwindcss(), sveltekit()]
});3. The entry CSS
@import 'tailwindcss';
@import '@nqmcreative/ui/theme.css';
@import '@nqmcreative/ui/fonts.css';
/* Tailwind v4 skips node_modules — point it at the package's dist so the
class names used inside the components are generated. */
@source '../node_modules/@nqmcreative/ui/dist';The @source line is not optional
4. Import the CSS once
<script lang="ts">
import '../app.css';
import Toaster from '@nqmcreative/ui/toaster';
let { children } = $props();
</script>
{@render children()}
<Toaster position="bottom-right" />5. Fonts and theme, before first paint
Both go in src/app.html, above %sveltekit.head%. Plain HTML rather than <svelte:head>, because Svelte parses a bare crossorigin attribute as boolean true and svelte-check rejects it.
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<script>
const saved = localStorage.getItem('nqm-theme');
if (saved === 'dark' || saved === 'light') document.documentElement.classList.add(saved);
</script>Using a component
Each component has its own subpath — the file name in kebab-case, so AvatarGroup is @nqmcreative/ui/avatar-group.
<script lang="ts">
import Button from '@nqmcreative/ui/button';
import Field from '@nqmcreative/ui/field';
import Input from '@nqmcreative/ui/input';
let email = $state('');
</script>
<Field label="Work email" hint="We only email about releases.">
<Input bind:value={email} placeholder="you@example.com" />
</Field>
<Button tone="accent">Get started</Button>The barrel works too:
import { Button, Field, Input } from '@nqmcreative/ui';Both produce the same bundle — measured on one app, barrel and subpaths came out byte-identical, because the barrel tree-shakes. Subpaths are about being explicit, and they cut the module graph the bundler walks.
The CLI
bunx nqm-ui list forms # every component in a category
bunx nqm-ui info date-picker # subpath, what it renders, what it imports
bunx nqm-ui add button badge # print the import lines
bunx nqm-ui add button --to src/routes/+page.svelteadd is a convenience, not an installer: after bun add the whole library is already there, and a component
pulls in whatever it renders internally. It writes the import line and tells you what comes along.
Updating
bun update @nqmcreative/uiOnly if you installed from GitHub
#sha, or clear the cache with bun pm cache rm. Installing from npm has no such problem.Other install routes
A packed tarball
Portable, and needs no repo access.
# in the library repo
bun run build && bun pm pack
# in your project
bun add ./nqmcreative-ui-0.1.0.tgzStraight from GitHub
Tracks main rather than a release. The repo is public,
so this needs no authentication — no SSH key, no token. git+https://github.com/… resolves to the same thing;
bun rewrites both to github:owner/repo#sha.
bun add github:mukhsamr/nqmcreative-uiA live symlink
For working on the library and an app at once. Use npm here — bun link and bun add file:<dir> both fail on Windows with EBUSY, because bun copies the whole source directory
into its cache.
npm install file:../path/to/nqmcreative-ui