Kin Form
Docs
INTRODUCTION
Getting Started Architecture

EXAMPLES
Basic Example Any-level Validation Dependent Field Validation Flexible Form Structures Flexible Field Components Array

API

Getting Started

What is Kin Form?

Kin Form is a library that makes working with forms easy in Lit applications.

It is packed with almost everything you need to create forms in a flexible, declarative, and type-safe way.

The name Kin Form is derived from my nickname (Kin), for the sake of simplicity. We all know how hard it is to name things!

Motivation

Kin Form started many years ago when I needed to build a complex admin portal using Lit for my company Accumulus. There were roughly 40 forms, ranging from simple ones with a few fields to complex ones with deeply nested objects and arrays. I couldn't find a robust form management library for Lit, so I decided to build my own.

After its success at Accumulus, I continued to refine the library and used it to build another admin portal for Restful Mind.

The library has served me so well that I believe it will benefit many others too. That's why I decided to turn it into an open source project.

Installation

Kin Form is available on jsr.

deno add jsr:@kin/form
pnpm add jsr:@kin/form # v10.9.0+
yarn add jsr:@kin/form # v4.9+
npx  jsr add @kin/form

Basic Usage

Here is a complete example of a simple login form to get you started.

First, ensure you have the necessary imports and that you have defined custom elements for your form fields (e.g., text-field). For simplicity, this example assumes you have a text-field component that extends FormField.

import { LitElement, html } from "lit";
import { customElement } from "lit/decorators.js";
import { FormController } from "@kin/form";

// Assumes the existence of a <text-field> component that extends KinField.
import "./text-field.ts";

interface User {
  email: string;
  name: string;
}

@customElement("login-form")
export class LoginForm extends LitElement {
  #form = new FormController<User>(this, {
    initialValue: {
      email: "",
      name: "",
    },
    onSubmit: async (form) => {
      // Simulate an API call.
      await new Promise((resolve) => setTimeout(resolve, 1000));
      alert(`Submitted: ${JSON.stringify(form.value, null, 2)}`);
    },
  });

  protected override render() {
    const { field, handleSubmit, submitting } = this.#form;

    return html`
      <text-field label="Email" ${field("email")}></text-field>

      <text-field label="Name" ${field("name")}></text-field>

      <button .disabled=${submitting} @submit=${handleSubmit}>
        ${submitting ? "Logging in..." : "Log in"}
      </button>
    `;
  }
}

Key Concepts

  1. FormController: This is the heart of your form. You create an instance of it in your Lit component, providing it with an initial data shape (initialValue) and a submission handler (onSubmit).

  2. field() directive: This directive binds a form field component (like <text-field>) to a specific property in your form's data model (e.g., email).

  3. handleSubmit(): This function, provided by the controller, orchestrates the submission process. It calls your onSubmit callback if the form is valid.

On this page

What is Kin Form? Motivation Installation Basic Usage
Created with ♥️ by  Man Hoang (Kin)