@groundbrick/svelte-ui
v0.4.2
Published
Reusable Svelte 5 UI components (design system): buttons, cards, alerts, badges, form fields, dropdowns, modals, empty states and more. Themeable via CSS variables.
Maintainers
Readme
@groundbrick/svelte-ui
Reusable Svelte 5 UI components (design system). Themeable via CSS variables,
extensible via props, class passthrough and snippets.
These components were extracted to be reused across projects. They have sensible default styling and behavior, but every visual aspect can be re-themed by overriding CSS custom properties.
Install (workspace)
// consumer app package.json
{
"dependencies": {
"@groundbrick/svelte-ui": "workspace:*"
}
}Build the package before the consuming app (the monorepo build runs packages first):
pnpm -F @groundbrick/svelte-ui buildPeer dependencies
| Dependency | Required | Notes |
| ---------------- | -------- | ------------------------------------------------------------------ |
| svelte | yes | ^5.25.0 (runes). |
| @200systems/shared | yes | Used by PhoneInput (phone parsing/formatting utilities). |
| bootstrap | optional | Components use Bootstrap 5 classes (.row, .dropdown, etc.). Load its CSS/JS in the app. |
| bootstrap-icons| optional | Some built-in icons use bi bi-* classes. |
The consuming app is responsible for loading Bootstrap and Bootstrap Icons (as the AgendaPet app already does in its root layout).
Theming
Import the default tokens once (e.g. in your root layout), then override any CSS variable to re-theme. Components reference tokens exclusively, so changing one token re-skins every component that uses it.
<script>
import '@groundbrick/svelte-ui/styles/tokens.css';
</script>
<!-- Re-theme a subtree (e.g. per-tenant branding) by overriding variables -->
<div style="--color-primary: #0aa; --radius-full: 8px;">
<Button>Themed button</Button>
</div>You can also skip the bundled tokens entirely and define your own
--color-primary, --spacing-*, --radius-*, --shadow-*, etc.
Usage
<script lang="ts">
import { Button, Card, CardBody, Alert, Badge, EmptyState } from '@groundbrick/svelte-ui';
import '@groundbrick/svelte-ui/styles/tokens.css';
let saving = $state(false);
</script>
<Card variant="elevated">
<CardBody>
<Alert variant="info">Welcome back!</Alert>
<Badge variant="success">Active</Badge>
<Button variant="primary" loading={saving} onclick={() => (saving = true)}>
Save
</Button>
</CardBody>
</Card>Components
| Component | Purpose |
| ------------------------------------------ | --------------------------------------------------- |
| Button | Button/link with variants, sizes and loading state. |
| Dropdown, DropdownItem | Bootstrap-based dropdown menu. |
| Card, CardHeader, CardBody, CardFooter | Card primitives. |
| FormField | Labelled input/textarea/select field. |
| PhoneInput | E.164 phone input with country selector. |
| DurationInput | Hours + minutes duration input. |
| AutocompleteInput | Async/debounced autocomplete field. |
| Badge | Pill/solid badges with variants. |
| EmptyState | Empty-state placeholder with illustration. |
| LoadingSpinner | Centered/full-screen spinner. |
| Container, Row, Col | Lightweight flex layout helpers. |
| Modal, Drawer | Overlays (with body scroll lock). |
| GridView | Responsive data grid: search, sort, pagination, drag-reorder, row actions. |
| EditableTable | Inline-editable table with add/remove rows. |
| PhotoUpload | Headless photo uploader (upload/remove/compress via callbacks). |
| PawPrintIcon | Inline SVG paw icon. |
Dependency-injection props (decoupled components)
Some components delegate app-specific concerns through props instead of importing app code:
GridView:resolveImageUrl(value, folder)(image cells),formatDate(value)(date cells, defaults to pt-PT),hasPermission(code)(row-action gating, defaults to allow-all).PhotoUpload(headless):onUpload(file, { folder })returns the uploaded URL,onRemove()deletes, optionalcompress(file, opts), plusonError/onFileSelected/onUploaded/onRemovednotifications.
Utilities
lockBodyScroll(),unlockBodyScroll()- reference-counted body scroll lock.minutesToHoursAndMinutes(),hoursAndMinutesToMinutes()- duration helpers.
Notes
- Components are decoupled from any app: permission/feature gating present in the
original AgendaPet
Button/DropdownItemwas intentionally removed here, and app utilities used byGridView/PhotoUploadare injected via props. GridViewkeeps the original Svelte 4 (export let) syntax; Svelte 5 runs it in legacy mode. All other components use runes.
