# Quick Start
A quick guide to getting started with SvSeeds.
> **Warning:** SvSeeds is currently in pre-release and may undergo breaking changes.
## Setup
There are two ways to use SvSeeds in your project.
### Prerequisites
SvSeeds is available with Svelte version 5.29.0 or higher.
### Package Installation
**npm**
```sh
npm install svseeds
```
**pnpm**
```sh
pnpm add svseeds
```
**yarn**
```sh
yarn add svseeds
```
### Local Installation (CLI)
**npm**
```sh
npx svseeds-cli
```
**pnpm**
```sh
pnpm dlx svseeds-cli
```
**yarn**
```sh
yarn dlx svseeds-cli
```
## Basic Usage
### Import
You can import unstyled components from SvSeeds. If you've copied the files locally, simply import them as regular components from your
project.
**CSS**
```svelte:MyButton.svelte
```
**TailwindCSS**
```svelte:MyButton.svelte
```
### Styling
SvSeeds provides two approaches for styling components. You can either apply CSS directly using the traditional method, or modify class
attributes (such as when using TailwindCSS). If you choose the CSS approach, styles must be defined in global scope.
**CSS**
```css:app.css
.my-button.whole {
padding-inline: 0.5rem;
border-radius: 0.25rem;
background-color: oklch(60% 0.118 184.704);
cursor: pointer;
}
.my-button.main {
color: #fff;
}
```
**TailwindCSS**
```ts:styles.ts
export { myButton };
const myButton = {
whole: "px-2 rounded-sm bg-teal-600 cursor-pointer",
main: "text-white",
};
```
### Demo of MyButton.svelte
## Next steps
- Ready to see the components in action? Browse [Gallery](/docs/gallery).
- Want to learn about styling? Explore [Styling](/docs/styling).
- Wondering about design thinking? Read about [Concepts](/docs/concepts).
- Looking to make it your own? Check out [Customization](/docs/customization).
---
# Concepts
## Background
SvSeeds was developed to help developers focus on application component functionality. By embedding SvSeeds components as "seeds" for common functionality, it provides an environment where developers can concentrate on what truly matters for their applications.
## Design Philosophy
### Standards-First Approach
Our fundamental philosophy is: **if standard HTML features are sufficient, use standard features instead of libraries**.
This approach is based on several key principles:
- Semantic HTML is recommended from an accessibility perspective
- Standard features provide familiar user experiences
- Native browser optimizations can be leveraged effectively
### Extending Standard Features
When standard features correspond to components, we build upon them as a foundation. For example:
- Disclosure component → Built on `details` and `summary` elements
- Modal component → Built on `dialog` element
- SelectField component → Built on `select` element
When no corresponding standard features exist, we build components from scratch while implementing proper accessibility support.
## Technical Features
### Headless Component Design
Based on the premise that styling requirements differ across projects, SvSeeds is designed as headless components that enable complete styling freedom.
### Separation of Functionality and Styling
For foundational components like buttons, we want to avoid the proliferation of similar component files within projects. To address this, SvSeeds adopts different approaches for **functionality** and **styling**:
#### Functionality: Structure Encapsulation
```svelte
{#each options.entries() as [value, label] (value)}
{label}
{/each}
```
By hiding internal structure from the outside:
- Code becomes easier to understand at a glance
- Custom component structure descriptions become simpler
- Eliminates the need for multiple component files with slightly different structures
- No need to be concerned with structure as long as it functions
This does not mean every component must be isolated. SvSeeds supports minimal nesting and composition where it clarifies ownership, such as placing a control inside its Field component or placing Disclosure children inside Accordion. The caller composes a small number of explicit children instead of describing a deep builder tree.
#### Styling: Complete Structure Access
Conversely, we provide access to all internal structures during styling:
- Enables detailed customization
- Minimizes constraints imposed by the library
- Eliminates the need for multiple component files with slightly different styles
To achieve this, we assign **part names** to each internal element, making them accessible during styling. Part names use abstract, unified naming for consistency.
A few components additionally include functional-only elements that are not part-named and do not appear in the component's Anatomy, such as a hidden `` used solely for form submission. These are neither styling nor user-control targets; they exist purely to make the control work.
### Variant-based Styling
To reduce the complexity of switching styling based on conditions, we provide functionality that automatically applies predefined styling based on component variants:
- Toggle button on/off variants
- Text input validation failure variants
- Other dynamic variant changes
This is achieved by giving each component variant properties and building a system that can apply styles defined for each variant.
### Library Components as Project Files
There are cases where you only need specific components. Adding an entire UI library to your project just for a few components can be excessive overhead. Additionally, there may be times when you want to make minor modifications to the internal workings of library components. By treating library components as files within your project, we can address these needs. Therefore, we've prepared a CLI tool that allows you to add components directly to your project.
## Summary
SvSeeds is a Svelte UI library that balances modern development requirements for functionality and customizability while respecting standard technologies. Through our approach of "hide functionality, expose styling," we provide an environment where developers can focus on the value creation they should be concentrating on.
---
# Gallery
Browse the categorized component catalog and find the building block you need.
## Form Controls
## Inputs
## Overlays
## Menu & Navigation
## Layout & Display
---
# Styling
SvSeeds components provide a flexible styling system. This document explains the two primary styling methods and their implementation details.
## Overview
### String-based Styling
Used when a string is specified for the `styling` prop, or when no value is provided. The specified class name is automatically applied to each part of the component. When no value is provided, the default component name is used.
### Object-based Styling
Used when an object of a specific type is specified for the `styling` prop. This allows you to specify classes individually for each part of the component. Use this approach when working with TailwindCSS.
## String-based Styling
In String-based Styling, the specified class name is applied in combination with each component part and variant.
### Example
**Basic Usage**
```svelte
```
Generated HTML (class attribute excerpt):
```html
```
**Conditional Styling Based on Variant**
```svelte
Hello
```
Generated HTML (class attribute excerpt):
```html
```
## Object-based Styling
In Object-based Styling, you can specify classes individually for each part of the component. For detailed object specifications, see [Object for Styling](#object-for-styling).
### Example
**Basic Usage**
```svelte
```
Generated HTML (class attribute excerpt):
```html
```
**Conditional Styling Based on Variant**
```svelte
Hello
```
Generated HTML (class attribute excerpt):
```html
```
## Part Name System
To ensure styling flexibility, all elements within components are assigned part names.
### Standard Part Names
The following part names are defined by default:
- `whole` - Overall component wrapper
- `top` - Top region
- `middle` - Middle region
- `bottom` - Bottom region
- `left` - Left area
- `main` - Main content area
- `right` - Right area
- `label` - Label part
- `aux` - Auxiliary part
- `extra` - Additional part
Since part names are defined as `string` type, custom components can also define custom part names. For the specific part names used by each component, refer to the individual component documentation.
## Variant System
Component styling adapts based on its current appearance variant.
### Standard Variants
The following variant names are defined by default:
- `neutral` - Default variant
- `active` - Active variant (such as selected state)
- `inactive` - Inactive variant (also used for invalid/error states)
Since variants are defined as `string` type, custom variants can also be used.
### Variant Behavior
Components fall into two categories: those that automatically manage their variant based on user interaction, and those that maintain a fixed variant. For detailed variant behavior of each component, refer to the individual component documentation.
#### Auto-Managing Components
Components like `Toggle` and `TextField` automatically update their variant in response to user interactions. For these components, the `variant` prop serves as an override for the default neutral variant.
#### Non-Auto-Managing Components
For these components, the `variant` prop directly sets the component's variant without any automatic changes.
## Theme-based Style Switching
Use CSS `prefers-color-scheme` to configure theme switching. For theme toggle functionality, refer to the [feature details](/docs/dark-toggle#feature-details) of the `DarkToggle` component.
## Animation & CSS Custom Properties
SvSeeds uses a shared convention for motion values and component-owned CSS custom properties. These props are set directly on the component, or on the child component that owns the motion, and CSS-expressible animation remains in caller CSS keyed off the existing part and variant classes.
`cssvar` maps a component-defined key to the CSS custom property name that component reads or writes. This lets you wire component internals to your own design tokens without changing the component's styling classes.
```svelte
```
`duration` sets time-based motion in milliseconds. Components that expose CSS-driven timing publish the reduced-motion-aware value through the canonical `--svs-duration` custom property.
```svelte
Content
```
`transition` is an escape hatch for JS-measured motion that CSS cannot express, such as auto-height or directional transitions. It accepts a `{ fn, params }` object; for example, Disclosure defaults to `slide` but can be swapped.
```svelte
Content
```
## Object for Styling
### Object Type
The object used in object-based styling is defined as the `SVSClass` type.
```svelte
```
### Advanced Class Value Specification
Property values can use clsx library-compatible values that are valid for [Svelte's class attribute](https://svelte.dev/docs/svelte/class) specification, as well as strings.
```ts
const styling = {
whole: ["whole-class", "class1", "class2"],
main: {
base: "main-class",
neutral: { foo, bar: !foo },
},
};
```
Do not confuse the two object shapes. A clsx condition object such as `{ foo, bar: !foo }` has boolean values and is one class value, used as the value of a single variant. The variant map, the object keyed by `base`, `neutral`, `active`, and so on, takes a `ClassValue` at each key; its values are never booleans.
### Fallback Variant Style
If the current variant is not found in the object, the style defined for `neutral` will be used as a fallback.
```svelte
Hello
```
Generated HTML (class attribute excerpt):
```html
```
### Shorthand Notation
You can omit the variant and specify class attribute values directly for part names:
```ts
const styling = {
whole: "whole-class",
main: "main-class",
};
```
This is interpreted as:
```ts
const styling = {
whole: {
base: "whole-class",
},
main: {
base: "main-class",
},
};
```
#### Important Note
Shorthand notation also accepts clsx condition objects directly. An object whose values are booleans, such as `{ foo, bar: !foo }`, is recognized as a class value and used as-is; no array wrapping is required:
```ts
const styling = {
whole: { foo, bar: !foo },
};
```
This is interpreted as:
```ts
const styling = {
whole: {
base: { foo, bar: !foo },
},
};
```
An object is treated as a variant map only when none of its values are booleans, for example `{ base: "base-class", active: "active-class" }`. Wrapping the object in an array still works and is an explicit way to force a plain class value:
```ts
const styling = {
whole: [{ foo, bar: !foo }],
};
```
---
# Customization
SvSeeds components offer flexible customization options, ranging from simple prop-based modifications to complete component overhauls.
## Using Props
### Basic Props Configuration
Each component comes with dedicated type definitions, allowing you to leverage TypeScript's type safety for customization.
```svelte
```
### Customizing Component Parts
Components that support specific parts (such as `left`, `right`, `bottom`, etc.) through props can be customized by specifying `Snippet` or `string` types for those parts. Only the specified parts will be rendered, with unnecessary elements automatically excluded.
#### Example of adding an icon to the left side:
```svelte
```
Generated HTML:
```html
```
#### Example of adding an icon to the right side:
```svelte
{#snippet right()}
⭐
{/snippet}
```
Generated HTML:
```html
```
### Attribute Customization
Base components accept standard HTML attributes as top-level props and forward unmatched attributes to their main element. Attributes that conflict with component-owned props or compromise component integrity may be omitted from the component type. Some wrapper or Field components expose narrower nested configuration for inner elements; check each component's documentation for those component-specific props.
```svelte
```
## Advanced Usage
### Direct Element Manipulation (Element Binding)
Components with an `element` prop allow direct manipulation of the main element using `bind:element`. Check each component's documentation to see which element the `element` prop binds to.
```svelte
```
### Applying Attachments
Components with an `attach` prop allow you to apply a Svelte `Attachment` to the main element. Check each component's documentation to see which element the attachment is applied to.
```svelte
```
### Customizing Dependent Components
Some wrapper components render default child components for data-driven usage. They customize those generated children through a typed, namespaced configuration prop whose value is the child props minus parent-owned props.
```svelte
{#snippet panel(_value: string)}
content
{/snippet}
```
## Direct Integration with CLI Tool
When you need deep customization that cannot be controlled through props, you can use the CLI tool to add components directly to your project. For details about the CLI tool, see [GitHub](https://github.com/scirexs/svseeds-cli).
### Using the CLI Tool
**npm**
```sh
npx svseeds-cli
```
**pnpm**
```sh
pnpm dlx svseeds-cli
```
**yarn**
```sh
yarn dlx svseeds-cli
```
### File Structure
By default, components are copied to the following location:
```text
project-root
└─ src
└─ lib
└─ _svseeds
├─ _core.ts # Shared functions & utilities
├─ NumberInput.svelte # Independent component
└─ NumberField.svelte # Component with dependencies
```
File naming conventions:
- `_core.ts`: Shared functions and utilities for all components
- Regular files: SvSeeds components (dependencies are automatically added)
### Setting Preset Styles
You can set the default style used when no `styling` prop is specified by modifying the generated `__PRESET` constant within the component. The value can be either a string or an `SVSClass` object.
```svelte
```
---
# Form Controls
SvSeeds provides form controls as **Field components** such as `TextField`. All Field components share a unified structure and validation functionality.
## Basic Structure
All Field components are composed of the following structured parts:
```text
whole (div) - Overall wrapper
├─ top - Wrapper for label elements
│ ├─ label - Label text
│ ├─ extra - Label supplement (e.g., "optional")
│ └─ aux - Additional information (e.g., character counter)
├─ middle - Input element wrapper
│ └─ main - Input element (Only CheckField has a different structure)
└─ bottom - Field description and error messages
```
Because `extra` is rendered inside the `label` element, it appears only when `label` is set; provide `label` whenever you use `extra`.
### Design Rationale
We use a `div` element for the `whole` container. We avoid using `fieldset` elements because they render an [anonymous fieldset content box](https://html.spec.whatwg.org/multipage/rendering.html#anonymous-fieldset-content-box), which complicates styling.
## Validation Features
Field components provide built-in validation functionality.
### Validation Function Type Definitions
TypeScript type definitions are provided for each Field component. Please refer to the individual component documentation for details.
### Validation Patterns
Field components support three validation patterns:
#### 1. Using Custom Functions
Validation runs immediately after user input. No validation occurs when the field value(s) is empty.
```svelte
```
#### 2. Using Attributes + Custom Functions
You can combine validation attributes with custom error messages.
```svelte
```
#### 3. Browser Native Validation
Standard browser validation messages are displayed during form submission.
```svelte
```
## Variant Transitions
The `variant` prop automatically transitions based on input state:
- `neutral` - Initial state or empty state
- `inactive` - Validation failed state
- `active` - Validation passed state
## Form-wide Validation
### Basic Pattern
When validating multiple Field components simultaneously, use a `form` element:
```svelte
```
### Integration with Button Component
Using SvSeeds' Button component allows for more concise code. When `onclick` is set on a Button, it only runs if `form?.checkValidity()` returns `true`.
```svelte
```
## Form Submission
To submit form data, set the `name` attribute directly on each Field component:
```svelte
```
---
# Utilities
This section documents the utility functions, constants, and other helper elements used within SvSeeds components.
## Available Exports
```ts
import { BASE, SR_ONLY, VARIANT, PARTS, shouldReduceMotion, canHover } from "svseeds";
import type { SVSClass, SVSVariant, SVSPart, SVSFieldValidation, SVSFieldConstraint, SVSContext, CollectionEvents, Position, Align, Vector } from "svseeds";
```
## Constants
These constants can be used with `SVSClass` objects for styling. See [Object for Styling](/docs/styling#object-for-styling) for details.
```ts
const BASE = "base";
const SR_ONLY =
"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;";
const VARIANT = Object.freeze({ NEUTRAL: "neutral", ACTIVE: "active", INACTIVE: "inactive" });
const PARTS = Object.freeze({
WHOLE: "whole",
MIDDLE: "middle",
MAIN: "main",
TOP: "top",
LEFT: "left",
RIGHT: "right",
BOTTOM: "bottom",
LABEL: "label",
AUX: "aux",
EXTRA: "extra",
});
```
`SR_ONLY` is a ready-made screen-reader-only CSS text for visually hidden content.
## Functions
### `shouldReduceMotion`
Checks whether the user prefers reduced motion. It returns `false` when `window` is unavailable, so motion is allowed by default under SSR.
```ts
function shouldReduceMotion(): boolean;
```
### `canHover`
Checks whether the primary pointer can hover. It returns `true` when `window` is unavailable, so hover is treated as available by default under SSR.
```ts
function canHover(): boolean;
```
## Types
### `SVSClass`
The `styling` prop type: a class string, or an object keyed by part. See [Object for Styling](/docs/styling#object-for-styling) for the full definition.
### `SVSVariant`
The component `variant` string: `VARIANT` values or any custom string.
```ts
type SVSVariant = (typeof VARIANT)[keyof typeof VARIANT] | (string & {});
```
### `SVSPart`
A component part name: `PARTS` values or any custom string.
```ts
type SVSPart = (typeof PARTS)[keyof typeof PARTS] | (string & {});
```
### `SVSFieldValidation`
A field validation callback returning an error message, or nullish when valid.
```ts
type SVSFieldValidation = (ctx: {
value: V;
validity: ValidityState;
element: E;
}) => string | undefined | null;
```
### `SVSFieldConstraint`
A per-item constraint callback for collection-style fields.
```ts
type SVSFieldConstraint = (ctx: {
value: string;
values: string[];
validity: ValidityState;
element: E;
}) => string | undefined | null;
```
### `SVSContext`
The shared component context exposing `variant` and `styling`.
```ts
type SVSContext = {
get variant(): SVSVariant;
get styling(): SVSClass | undefined;
};
```
### `CollectionEvents`
The `onadd` and `onremove` event contract for collection-style components. Return the subset to commit.
```ts
interface CollectionEvents {
// Return the subset to commit: undefined => all, [] => none.
onadd?: (detail: { values: T[]; added: T[] }) => T[] | void;
onremove?: (detail: { values: T[]; removed: T[] }) => T[] | void;
}
```
### `Position`
A box-side placement string used by positioning components.
```ts
type Position = "top" | "right" | "bottom" | "left";
```
### `Align`
Cross-axis alignment along the chosen side.
```ts
type Align = "start" | "center" | "end";
```
### `Vector`
A 2-D point / offset in pixels.
```ts
type Vector = { x: number; y: number };
```
---
# Accordion
A container with multiple collapsible sections where only one section can be expanded at a time.
## Usage
Wrap one or more `Disclosure` children.
```svelte
ContentContent
```
If you do not need open/close animation or programmatic state tracking, native `` elements already give exclusive single-open behavior on their own; reach for Accordion only when you need those extras.
## Anatomy
The `class` attribute values represent `part` names. Other attributes represent their corresponding props.
```svelte
```
### Dependency
- [Disclosure](/docs/disclosure)
## Props
| Name | Type | Default | Description |
|---|---|---|---|
| `items` | `AccordionItem[]` | - | Data-mode array of `AccordionItem`; each item has a unique `value` addressed by `current`, a `label` as string / `Snippet<[open, variant]>` / component, a `panel` as `Snippet<[variant]>` / component, and optional `inactive` |
| `children` | `Snippet` | - | Declarative mode: place `` children directly; when both `children` and `items` are supplied, `children` wins |
| `current` | `string` | - | Bindable `value` of the open item; `undefined` means all closed. Accordion is exclusive (at most one item open at a time) |
| `styling` | `SVSClass` | - | Styling override |
| `variant` | `SVSVariant` | `NEUTRAL` | Variant |
| `disclosure` | `DisclosureProps` | - | Default props applied to the data-mode inner `Disclosure` |
## Styling
To learn more, see [Styling](/docs/styling).
### Variant Management
No automatic switching.
### Default Class Name
`svs-accordion`
Internal dependent components combine the parent class with their own default class names, resulting in multiple classes (e.g., `svs-accordion svs-disclosure`).
## Behavior
Declarative `` children automatically coordinate exclusive open state through `current` and inherit the base `variant`/`styling`.
## Accessibility
### ARIA Roles and Attributes
The component applies these automatically:
- Accordion (`whole` `
`): `role="group"`.
Each item is a `Disclosure` child. See [Disclosure](/docs/disclosure) for each item's ARIA attributes and keyboard behavior.
### Standards Basis
Accordion items are built on native `` / `` through Disclosure, so keyboard and assistive-technology support follows the browser standard for disclosure controls. See the [Concepts standards-first guidance](/docs/concepts) for the library's approach.
## Exports
### Types
```ts
type AccordionComponent = { component: Component; props?: Record };
type AccordionItem = {
value: string; // REQUIRED, unique within `items`. Addresses `current`.
label: string | Snippet<[boolean, string]> | AccordionComponent;
panel: Snippet<[string]> | AccordionComponent;
inactive?: string | boolean; // (false) reason string OR true; forwarded to Disclosure
};
interface AccordionProps {
items?: AccordionItem[];
children?: Snippet;
current?: string; // bindable, undefined = all closed
styling?: SVSClass;
variant?: SVSVariant; // (VARIANT.NEUTRAL)
disclosure?: Omit;
}
type AccordionReqdProps = never;
type AccordionBindProps = "current";
```
### Others
No additional exports are available.
## Examples
The example code uses Tailwind CSS along with `SVSClass`.
### Basic
**Code**
```svelte src=AccordionBasic.svelte
{#snippet panel1(_variant: string)}
Diam facilisi consequat sadipscing in. Illum eleifend sit sit lorem takimata diam ut vel amet elitr duo.
{/snippet}
{#snippet panel2(_variant: string)}
Justo sea et. Sea est accusam sanctus feugait sed dolore lorem consectetuer est.
{/snippet}
{#snippet panel3(_variant: string)}
No dolore aliquip et aliquip sed lorem et qui nihil dolor sit lorem no sit. Esse sed ipsum et diam takimata.
{/snippet}
```
### With Interactive Variant
**Code**
```svelte src=AccordionPract.svelte
{#snippet label1(open: boolean, _variant: string)}
First Item
{@render icon(open)}
{/snippet}
{#snippet label2(open: boolean, _variant: string)}
Second Item
{@render icon(open)}
{/snippet}
{#snippet label3(open: boolean, _variant: string)}
Third Item
{@render icon(open)}
{/snippet}
{#snippet panel1(_variant: string)}
Diam facilisi consequat sadipscing in. Illum eleifend sit sit lorem takimata diam ut vel amet elitr duo.
{/snippet}
{#snippet panel2(_variant: string)}
Justo sea et. Sea est accusam sanctus feugait sed dolore lorem consectetuer est.
{/snippet}
{#snippet panel3(_variant: string)}
No dolore aliquip et aliquip sed lorem et qui nihil dolor sit lorem no sit. Esse sed ipsum et diam takimata.
{/snippet}
{#snippet icon(open: boolean)}
{/snippet}
```
---
# Button
A clickable element that triggers an action when pressed.
## Usage
Use standalone.
```svelte
```
## Anatomy
The `class` attribute values represent part names, and `conditional` indicates elements that are rendered conditionally. Other attributes represent their corresponding props.
```svelte
```
## Props
| Name | Type | Default | Description |
|---|---|---|---|
| `children*` | `Snippet` | - | Main label; receives the variant as its argument |
| `left` | `Snippet` | - | Content before the label |
| `right` | `Snippet` | - | Content after the label |
| `type` | `` | `"button"` | The button's `type` attribute |
| `onclick` | `MouseEventHandler` | - | Click handler; suppressed while `inactive` is set |
| `form` | `HTMLFormElement` | - | Form validated on click ([Details](/docs/form-controls#form-wide-validation)) |
| `inactive` | `string` | - | Non-empty reason marks `aria-disabled`, suppresses `onclick`, and forces the `inactive` variant (restored when cleared) |
| `attach` | `Attachment` | - | Svelte attachment on the root button |
| `element` | `HTMLButtonElement` | - | Bindable root element |
| `styling` | `SVSClass` | - | Styling override |
| `variant` | `SVSVariant` | `NEUTRAL` | Bindable variant |
`*` required. Other `HTMLButtonAttributes` are passed to `