How to Use

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:

Plain 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

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.

Svelte
<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.

Svelte
<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.

Svelte
<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 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
<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.

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

Svelte
<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>