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:
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
Design Rationale
We use a div
element for the whole
container. We avoid using fieldset
elements because they render an 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.
<script lang="ts">
import { TextField, type TextFieldValidation } from "svseeds";
const validations: TextFieldValidation[] = [
(value: string) => [...value].length > 10 ? "Please enter 10 characters or less" : "",
(value: string) => !value ? "This field is required" : "",
];
</script>
<TextField {validations} />
2. Using Attributes + Custom Functions
You can combine validation attributes with custom error messages.
<script lang="ts">
import type { HTMLInputAttributes } from "svelte/elements";
import { TextField, type TextFieldValidation } from "svseeds";
const validations: TextFieldValidation[] = [
(value: string, validity: ValidityState) => {
if (validity.tooLong) return "Please enter 10 characters or less";
if (validity.valueMissing) return "This field is required";
}
];
const attributes: HTMLInputAttributes = {
maxlength: 10,
required: true,
};
</script>
<TextField {validations} {attributes} />
3. Browser Native Validation
Standard browser validation messages are displayed during form submission.
<script lang="ts">
import type { HTMLInputAttributes } from "svelte/elements";
import { TextField } from "svseeds";
const attributes: HTMLInputAttributes = {
maxlength: 10,
required: true,
};
</script>
<TextField {attributes} />
Variant Transitions
The variant
prop automatically transitions based on input state:
neutral
- Initial state or empty stateinactive
- Validation failed stateactive
- Validation passed state
Form-wide Validation
Basic Pattern
When validating multiple Field components simultaneously, use a form
element:
<script lang="ts">
import { TextField } from "svseeds";
let form = $state();
const validations = [
(value: string) => !value ? "This field is required" : "",
];
const onclick = () => form?.checkValidity();
</script>
<form bind:this={form}>
<TextField {validations} />
<TextField {validations} />
<button type="button" {onclick}>Validate</button>
</form>
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
.
<script lang="ts">
import { Button, TextField } from "svseeds";
let form = $state();
const validations = [
(value: string) => !value ? "Input is required" : "",
];
const onclick = () => console.log("OK");
</script>
<form bind:this={form}>
<TextField {validations} />
<TextField {validations} />
<Button bind:form {onclick}>Validate</Button>
</form>
Form Submission
To submit form data, set the name
attribute using the attributes
prop:
<script lang="ts">
import { Button, TextField } from "svseeds";
let form = $state();
</script>
<form bind:this={form} method="post" action="/submit">
<TextField attributes={{ name: "username" }} />
<TextField attributes={{ name: "email" }} />
<Button type="submit" bind:form>Submit</Button>
</form>