npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sio-group/form-builder

v0.1.3

Published

[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC) ![npm](https://img.shields.io/npm/v/@sio-group/form-builder) ![TypeScript](https://img.shields.io/badge/types-Yes-brightgreen)

Readme

@sio-group/form-builder

License: ISC npm TypeScript

A fully typed, fluent API form builder for generating structured form definitions in TypeScript. This package is the foundation of the @sio-group/form-react component, but can be used independently with any rendering layer (React, Vue, Svelte, or server-side rendering).

Building complex forms often starts with defining their structure. While you could write a plain array of field objects, ensuring type-safety for every field's specific configuration (like min/max for numbers or options for selects) is tedious and repetitive. @sio-group/form-builder provides a fluent and fully typed API to define this structure, letting you focus on what fields you need, not how to type them correctly.


Installation

npm install @sio-group/form-builder

Quick Example

import { formBuilder } from '@sio-group/form-builder';

const form = formBuilder()
  .addText('firstName', { 
    label: 'First name', 
    required: true, 
    placeholder: 'John' 
  })
  .addEmail('email', { 
    label: 'Email', 
    required: true 
  })
  .addSelect('role', { 
    label: 'Role', 
    options: ['Admin', 'Editor', 'User'] 
  })
  .getFields();

console.log(form);

Output:

[
  {
    "name": "firstName",
    "type": "text",
    "config": {
      "label": "First name",
      "required": true,
      "placeholder": "John"
    }
  },
  {
    "name": "email",
    "type": "email",
    "config": {
      "label": "Email",
      "required": true
    }
  },
  {
    "name": "role",
    "type": "select",
    "config": {
      "label": "Role",
      "options": ["Admin", "Editor", "User"]
    }
  }
]

API

Create Builder

const builder = formBuilder();

Returns a new FormBuilder instance.

Retrieve Fields

builder.getFields();

Returns a copy of the internal field array.

Supported Field Types

Text Inputs

addText(name, config)
addSearch(name, config)
addEmail(name, config)
addTelephone(name, config)
addPassword(name, config)
addUrl(name, config)

Example

builder.addText('username', { 
  label: 'Username', 
  required: true
});

Numeric Inputs

addNumber(name, config)
addRange(name, config)

Example

builder.addNumber('age', { 
  min: 18, 
  max: 99, 
  step: 1
});

Date & Time

addDate(name, config)
addTime(name, config)
addDateTime(name, config)

Example

builder.addDate('birthdate', { 
  min: '1900-01-01', 
  max: '2025-01-01'
});

Select & Choice

addSelect(name, config)
addCreatable(name, config)
addRadio(name, config)
addCheckbox(name, config)

Example

builder.addSelect('country', { 
  options: [
    { label: 'Belgium', value: 'be' }, 
    { label: 'Netherlands', value: 'nl' }
  ], 
  multiple: false
});

Textarea

addTextarea(name, config)

Example

builder.addTextarea('bio', { 
  rows: 4
});

File

addFile(name, config)

Example

builder.addFile('avatar', { 
  accept: 'image/*', 
  multiple: false
});

Other

addColor(name, config)
addHidden(name, config)

Configuration Model

All fields accept an optional configuration object. If you don't need any configuration, you can simply pass the field name:

formBuilder()
  .addText('firstName')                    // ✅ Minimal: just the name
  .addEmail('email', { required: true })   // ✅ With configuration
  .getFields();

When provided, the configuration object extends the base interface:

interface Base<T extends InputTypes> { 
  defaultValue?: ValueTypes<T>;
  label?: string;
  placeholder?: string;
  description?: string;
  icon?: string;
  required?: boolean;
  disabled?: boolean;
  readOnly?: boolean;
  className?: string;
  autocomplete?: string;
}

Required Configuration

Some field types require additional configuration:

| Field Type | Required Properties | |------------------|-----------------------------------------| | addSelect() | options (array of strings or objects) | | addCreatable() | options (array of strings or objects) | | addRadio() | options (array of strings or objects) |

Example

// ✅ Valid: options provided
builder.addSelect('country', { 
  options: ['Belgium', 'Netherlands']
});

// ❌ Invalid: options missing
builder.addSelect('country', {});  // Type error!
builder.addSelect('country');      // Type error!

Optional Field-Specific Properties

Other field types may add optional properties such as:

  • min, max, step
  • multiple
  • accept
  • filesize
  • rows, cols
  • etc.

Example of field-specific configuration:

// Textarea has optional 'rows' and 'cols'
const textareaConfig = { label: 'Bio', rows: 5, placeholder: 'Tell something about yourself...' };

// Number has optional 'min', 'max' and 'step'
const numberConfig = { min: 18, max: 99 };

Type Safety

The builder is fully generic and enforces:

  • Correct config per field type
  • Correct defaultValue type per input
  • Valid option structures for select/radio fields
  • Strong compile-time guarantees

Example of invalid usage:

builder.addNumber('age', { 
  min: '18' // ❌ Type error
});

Chaining

All addX methods return the builder instance:

formBuilder()
.addText('firstName', { label: 'First name' })
.addEmail('email', { label: 'Email' })
.addPassword('password', { label: 'Password' })
.getFields();

Architecture

The builder stores fields internally as:

FormField<InputTypes>[]

Each field has:

{
  name: string
  type: InputTypes
  config: FieldConfigMap[T]
}

This makes the library:

  • UI framework agnostic
  • SSR friendly
  • Easily serializable
  • Suitable for headless form rendering

Ecosystem

@sio-group/form-builder is the core of the SIO Form ecosystem:

This modular approach lets you use the same form definitions across different frameworks or even generate server-side validated forms from the same structure.

Intended Usage Pattern

This package defines form structure only. It is the core building block for framework-specific renderers like @sio-group/form-builder-react.

It does not:

  • Render UI
  • Handle validation
  • Manage form state
  • Perform submission logic

It is intended to be consumed by a renderer (e.g. React adapter).

Example Integration (React)

const fields = formBuilder()
  .addText('firstName', { label: 'First name' })
  .addEmail('email', { label: 'Email' })
  .getFields();

return (
  <>
    {fields.map(field => (
      <MyFieldRenderer key={field.name} field={field} />
    ))}
  </>
);

Contributing

Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.

License

This project is licensed under the ISC License - see the LICENSE file for details.