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

@harnessio/forms

v0.4.5

Published

Harness Forms Library

Readme

Harness forms

This repository contains components and utilities for creating forms in the harness applications.

Intro

The library uses form configuration schema and inputs to generate form. For json schema driven forms, we are use parser to convert input data to form configuration schema data model. This means that for any kind of form we have to create form configuration schema either explicitly or implicitly by transforming input data.

Principles

  • Form is generated from configuration.
  • Validation is part of configuration (per input).
  • Default values are part of configuration (per input).
  • Each input defines its configuration interface.
  • Input define default validation as utility function - optional.

Step by step guide

1. Input type

Each input has a unique type.

export enum InputType {
  text = "text",
  number = "number",
  checkbox = "checkbox",
  connector = "connector"
  ...
}

2. Create inputs

Examples of input can be found in the playgorund: Text input example

Minimal implementation:

import { InputComponent, InputProps, useController, type AnyFormValue } from '@harnessio/forms'

export interface TextInputConfig {
  inputType: InputType.text
}

function TextInputInternal(props: InputProps<AnyFormValue>): JSX.Element {
  const { readonly, path, input } = props
  const { label = '', required, placeholder } = input

  const { field, formState } = useController<{ [key: string]: boolean }>({
    name: path
  })

  return (
    <>
      <label>{label}</label>
      <input placeholder={placeholder} {...field} disabled={readonly} tabIndex={0} />
    </>
  )
}

export class TextInput extends InputComponent<AnyFormValue> {
  public internalType = InputType.text

  renderComponent(props: InputProps<AnyFormValue>): JSX.Element {
    return <TextInputInternal {...props} />
  }
}

3. Register inputs

Use InputFactory to register inputs

import { InputFactory } from '@harnessio/forms'

import { TextInput } from '../inputs/TextInput'

const inputComponentFactory = new InputFactory()
inputComponentFactory.registerComponent(new TextInput())

export default inputComponentFactory

4. Create form model - IFormDefinition

Form model is a blueprint for creating form.

export const formDefinition: IFormDefinition = {
  inputs: [
    {
        inputType: InputType.string,
        path: "name",
        label: "Name",
    },
    {
        inputType: InputType.number,
        path: "age",
        label: "Age",
    }
  ]
}

NOTE: Input may contain configuration. In this case we have to provide a generic type to IFormDefinition in order to get intellisense for the form definition inputs.

// 1. Define input config type
export interface ListInputConfig {
  inputType: InputType.list
  inputConfig: {
    inputs: UIInputWithConfigsForList[]
    layout?: 'grid' | 'default'
  }
}

// 2. Use input config type for second generic of component props
function ListInputInternal(props: InputProps<AnyFormValue, ListInputConfig>): JSX.Element ....

// 3. Make union of all Input configs
export type InputConfigType =
  | ListInputConfig
  | TextInputConfig ...

// 4. Use union type when defining form
export const formDefinition: IFormDefinition<InputConfigType> = {
  inputs: [...]
}

For more info check List input example

5. Render form

Use RootForm and RenderForm components.

<RootForm initialValues={{}} onSubmit={handleOnSubmit}>
  <RenderForm factory={inputComponentFactory} inputs={formDefinition} />
</RootForm>

Configure Required validation

Required validation can be configured globally for all inputs or per input. Per input validation overrides the global validation.

When the library is generating validation, it tries to pick the first available validation for required check in this order:

  • requiredSchemaPerInput
  • requiredSchema
  • default - if validation is not found, it uses the default built-in validation.
// Required validation config example
const validationConfig: IGlobalValidationConfig = {
  requiredSchemaPerInput: {
    [InputType.string]: zod.string(),
    [InputType.number]: zod.number(),
    [InputType.myCustomInput]: zod.custom(....),
  },
  requiredSchema: zod.custom(....), // << used for validating all inputs except string, number and myCustomInput
};

If validation configuration is not found, default/built-in validation takes place. Message can be set globally or per input.

// Required message config example

const validationConfig: IGlobalValidationConfig = {
  requiredMessage: "Required field",
  requiredMessagePerInput: {
    [InputType.string]: "Field is required",
    [InputType.number]: "Required. Please enter a number",
  },
};