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

yg-sdui-forms

v1.0.1

Published

React UI Component Library using React Hook Form

Readme

yg-sdui-forms 🚀

A lightweight, configuration-driven React form library built on top of React Hook Form. It makes forms completely configurable so that their structure, validations, and visibility rules can be managed via JSON configuration without modifying React code.


🔗 Quick Links


🧠 Server-Driven UI (SDUI)

Server-Driven UI is an architectural pattern where the server sends a JSON configuration describing which pre-built UI components should be rendered and how they should behave.

Core Architecture Layers:

  1. Component Library: Pre-built UI components.
  2. Component Mapper: Registry mapping configuration strings (c_name) to React components.
  3. Component Renderer: Reads the JSON configuration and instantiates the mapped components with their configured props.

⚡ State Management

Form state is divided into:

  • Server State: API updates, caching, and background queries (best managed by tools like TanStack Query).
  • Local State: Immediate user inputs, validations, and dynamic layouts inside forms (managed by React Hook Form).

Why React Hook Form?

  • Zero Boilerplate: Uses dot-notation paths (e.g., accountDetail.username) to register nested objects automatically.
  • Performance: Minimizes unnecessary re-renders.
  • Validation: Supports standard HTML validation attributes (required, minLength, pattern, etc.).

👁️ Dynamic Visibility Rules

Define conditional visibility rules directly within the JSON configuration:

{
  "c_name": "TextInput",
  "path": "profile.restrictedBio",
  "label": "Restricted Bio",
  "visibility": "profile.age",
  "value": 18
}

How It Works:

  • The <FormRenderer /> component checks the visibility and value properties.
  • It uses useWatch to listen to the field path specified by visibility.
  • If the watched field's value equals the target value, the component is rendered. Otherwise, it returns null.
  • Note: For backwards compatibility, the legacy nested format Visibility: { field: "path", value: val } is also supported.

🚀 Getting Started

1. Installation

Install the package alongside react-hook-form:

npm install yg-sdui-forms react-hook-form

2. Basic Setup

Wrap the form in react-hook-form's FormProvider and render fields using <FormRenderer />.

import React from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { FormRenderer } from 'yg-sdui-forms';

const formFields = [
  {
    c_name: 'TextInput',
    path: 'accountDetail.username',
    label: 'Username',
    placeholder: 'Enter your username',
    validation: { required: 'Username is required' }
  },
  {
    c_name: 'EmailInput',
    path: 'accountDetail.email',
    label: 'Email Address',
    placeholder: 'Enter your email',
    validation: { required: 'Email is required' }
  }
];

function MyForm() {
  const methods = useForm({
    defaultValues: {
      accountDetail: { username: '', email: '' }
    }
  });

  const onSubmit = (data) => {
    console.log('Submitted Data:', data);
  };

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(onSubmit)}>
        {/* Render fields dynamically */}
        <FormRenderer fields={formFields} />
        
        <button type="submit" style={submitBtnStyle}>Submit</button>
      </form>
    </FormProvider>
  );
}

const submitBtnStyle = {
  padding: '10px 20px',
  backgroundColor: '#6366f1',
  color: '#fff',
  border: 'none',
  borderRadius: '6px',
  cursor: 'pointer',
  fontWeight: '600'
};

📦 Component Catalog

yg-sdui-forms includes 18 pre-styled components categorized for form data capture. Every component is designed with standard focus states, custom toggle behaviors, and validation error styling.

1. Text & Numeric Inputs

| Component Name (c_name) | Purpose / Description | Key Props / Behaviors | | :--- | :--- | :--- | | TextInput | General single-line input field. | placeholder, standard input props | | Textarea | Multi-line text field. | rows (defaults to 4) | | NumberInput | Input constraint for numbers. | min, max, step | | EmailInput | Specialized email input field. | Auto type validation | | PasswordInput | Secure entry with an eye toggle. | Toggle visibility button | | PhoneInput | Country code and flag selector. | Dynamic country flag alignment | | URLInput | Input with a prefix badge (https://). | Prefix labels | | SearchInput | Search field with clean icon integration. | - |

2. Selection Components

| Component Name (c_name) | Purpose / Description | Config Options | | :--- | :--- | :--- | | Select | Dropdown single selection list. | options: [{ value, label }] | | MultiSelect | Dropdown list returning selected items as pills. | options: [{ value, label }] | | RadioGroup | Radio button group. | options, layout ('vertical' | 'horizontal') | | Checkbox | Single checkbox returning boolean. | Standard checked behavior | | CheckboxGroup | Multiple checkboxes returning string arrays. | options, layout ('vertical' | 'horizontal') | | ToggleSwitch | iOS-style sliding boolean switch. | - |

3. Date & Time Components

| Component Name (c_name) | Purpose / Description | Key Props / Behaviors | | :--- | :--- | :--- | | DatePicker | Calendar dropdown selection. | Native date input | | TimePicker | Digital clock input. | Native time input | | DateTimePicker | Combination calendar and clock. | Native datetime-local input | | DateRangePicker | Dual calendar selection for start/end dates. | startPath, endPath, startLabel, endLabel |


⚙️ Schema Reference

Every field item in your schema configuration array should follow this structure:

| Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | c_name | string | Yes | The component name matching the registry (e.g. 'TextInput'). | | path | string | Yes | Dot-notation nested state binding path (e.g. 'profile.bio'). Note: Excluded in DateRangePicker in favor of startPath/endPath. | | label | string | No | Label text rendered above the field. | | placeholder| string | No | Suggestive input help text. | | visibility | string | No | The field path to watch for conditional visibility. | | value | any | No | The target value for the visibility condition. If the watched field's value equals this, the field is shown. | | validation | object | No | Hook form validators: { required, min, max, pattern, minLength, maxLength }. |


🛠️ Showcase Example

Here is a comprehensive form configuration representing a nested registration system with conditional visibility:

const userRegistrationConfig = [
  {
    c_name: 'TextInput',
    path: 'auth.username',
    label: 'Username',
    placeholder: 'username',
    validation: { required: 'Username is required' }
  },
  {
    c_name: 'PasswordInput',
    path: 'auth.security.password',
    label: 'Account Password',
    placeholder: 'Minimum 8 characters',
    validation: { 
      required: 'Password is required', 
      minLength: { value: 8, message: 'Password is too short' } 
    }
  },
  {
    c_name: 'NumberInput',
    path: 'personal.age',
    label: 'Age',
    placeholder: '21',
    validation: { required: 'Please specify age' }
  },
  {
    c_name: 'Textarea',
    path: 'personal.restrictedBio',
    label: 'Special Bio (Only visible for 18-year-olds)',
    placeholder: 'Tell us your story...',
    visibility: 'personal.age',
    value: 18
  },
  {
    c_name: 'MultiSelect',
    path: 'preferences.techStack',
    label: 'Preferred Technologies',
    options: [
      { value: 'react', label: 'React.js' },
      { value: 'node', label: 'Node.js' },
      { value: 'ts', label: 'TypeScript' },
      { value: 'rust', label: 'Rust' }
    ],
    validation: { required: 'Choose at least one technology' }
  },
  {
    c_name: 'DateRangePicker',
    startPath: 'vacation.start',
    endPath: 'vacation.end',
    label: 'Scheduled Leave',
    startLabel: 'Leave Starts',
    endLabel: 'Leave Ends'
  }
];

🔌 Extending with Custom Components

Extend the library by registering custom components to componentMap:

import { componentMap, FormRenderer } from 'yg-sdui-forms';

// 1. Define custom React input
const CustomRatingInput = ({ path, label }) => {
  return (
    <div>
      <label>{label}</label>
      {/* custom register fields */}
    </div>
  );
};

// 2. Register it with the componentMap dictionary
componentMap['RatingInput'] = CustomRatingInput;

// 3. Use in JSON configuration
const config = [
  {
    c_name: 'RatingInput',
    path: 'feedback.stars',
    label: 'Rate your experience'
  }
];