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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@stvnprkns/formless-registry

v0.1.1

Published

Semantic form schema registry for Formless - A type-safe registry for form field definitions with metadata

Downloads

5

Readme

@stvnprkns/formless-registry

A type-safe, semantic form field registry for Formless applications. This package provides a centralized registry of form field definitions with rich metadata, validation rules, and type information.

Features

  • 🏷️ Type-Safe: Built with TypeScript for excellent developer experience
  • 📝 Rich Metadata: Each field includes type information, validation rules, labels, and more
  • 🗂️ Categorized: Organize fields into logical groups (Personal, Account, Address, etc.)
  • 🔄 Versioned: Track field additions and changes
  • ⚠️ Deprecation Support: Mark fields as deprecated while maintaining backward compatibility
  • 🧪 Tested: Comprehensive test coverage
  • 📦 Tree-shakeable: Only bundle what you use
  • 🌐 Universal: Works in both Node.js and browser environments
  • 📱 Framework Agnostic: Use with any frontend framework or vanilla JS

Installation

# Using npm
npm install @stvnprkns/formless-registry

# Using yarn
yarn add @stvnprkns/formless-registry

# Using pnpm
pnpm add @stvnprkns/formless-registry

Table of Contents

Quick Start

Basic Usage

import { formlessRegistry } from '@stvnprkns/formless-registry';

// Access field definitions
const emailField = formlessRegistry.fields.email;
console.log('Email Field:', {
  label: emailField.label,
  type: emailField.type,
  required: emailField.required,
  pattern: emailField.pattern
});

// Check registry version
console.log('Registry Version:', formlessRegistry.version);

// List all available fields
console.log('Available Fields:', Object.keys(formlessRegistry.fields));

Accessing Fields by Category

// Get all personal information fields
const personalFields = Object.entries(formlessRegistry.fields)
  .filter(([_, field]) => field.category === 'personal')
  .map(([key, field]) => ({
    key,
    label: field.label,
    type: field.type
  }));

console.log('Personal Information Fields:', personalFields);

API Reference

formlessRegistry

The main registry object that contains all field definitions and metadata.

Properties

// Current version of the registry
version: string;

// Object containing all field definitions
fields: Record<string, FieldConfig>;

// Object containing category metadata (if any)
categories?: Record<string, CategoryConfig>;

// Additional metadata about the registry
meta?: {
  name?: string;
  description?: string;
  [key: string]: any;
};

FieldConfig

Interface representing a field configuration:

interface FieldConfig {
  // The type of the field (e.g., 'text', 'email', 'select')
  type: FieldType;
  
  // Human-readable label for the field
  label: string;
  
  // Description or help text
  description?: string;
  
  // Whether the field is required
  required?: boolean;
  
  // Validation pattern (regex string)
  pattern?: string;
  
  // Error message when pattern validation fails
  patternMessage?: string;
  
  // Category for grouping related fields
  category?: string;
  
  // Whether the field is deprecated
  deprecated?: boolean;
  
  // Version when this field was added
  version?: string;
  
  // Example values for the field
  examples?: any[];
  
  // Additional field-specific options
  [key: string]: any;
}

CategoryConfig

interface CategoryConfig {
  // Display name for the category
  label: string;
  
  // Optional description
  description?: string;
  
  // Additional metadata
  [key: string]: any;
}

Field Configuration

Each field in the registry is a FieldConfig object with properties like:

{
  "email": {
    "type": "email",
    "label": "Email Address",
    "description": "A valid email address",
    "required": true,
    "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
    "patternMessage": "Please enter a valid email address",
    "category": "account",
    "examples": ["[email protected]"],
    "deprecated": false,
    "version": "1.0.0"
  }
}

Categories

The registry organizes fields into logical categories for easier management:

  • personal: Personal Information (name, date of birth, etc.)
  • account: Account Information (email, username, password)
  • address: Physical Address (street, city, zip code)
  • payment: Payment Information (credit card, billing details)
  • preferences: User Preferences (language, theme, notifications)
  • other: Additional Information

TypeScript Support

The package includes TypeScript type definitions. Import types like this:

import type { FieldConfig, FieldType, FormlessSchema } from '@stvnprkns/formless-registry';

// Example of using types
function validateField(field: FieldConfig, value: any): boolean {
  if (field.required && !value) return false;
  if (field.pattern && value) {
    const regex = new RegExp(field.pattern);
    return regex.test(value);
  }
  return true;
}

Examples

1. Form Generation

function renderForm(fields: string[]) {
  return fields.map(fieldKey => {
    const field = formlessRegistry.fields[fieldKey];
    if (!field) return null;
    
    return `
      <div class="form-group">
        <label for="${fieldKey}">
          ${field.label}
          ${field.required ? '<span class="required">*</span>' : ''}
        </label>
        <input 
          type="${field.type}" 
          id="${fieldKey}" 
          name="${fieldKey}" 
          ${field.required ? 'required' : ''}
          ${field.pattern ? `pattern="${field.pattern}"` : ''}
          placeholder={field.placeholder || ''}
        />
        {field.description && (
          <div class="help-text">${field.description}</div>
        )}
      </div>
    `;
  }).join('\n');
}

2. Field Validation

function validateForm(data: Record<string, any>) {
  const errors: Record<string, string> = {};
  
  Object.entries(data).forEach(([fieldKey, value]) => {
    const field = formlessRegistry.fields[fieldKey];
    if (!field) return;
    
    if (field.required && !value) {
      errors[fieldKey] = `${field.label} is required`;
      return;
    }
    
    if (field.pattern && value) {
      const regex = new RegExp(field.pattern);
      if (!regex.test(value)) {
        errors[fieldKey] = field.patternMessage || 'Invalid format';
      }
    }
  });
  
  return Object.keys(errors).length > 0 ? errors : null;
}

3. Dynamic Form with React

import React from 'react';
import { formlessRegistry } from '@stvnprkns/formless-registry';

function DynamicForm() {
  const [formData, setFormData] = React.useState({});
  const [errors, setErrors] = React.useState({});

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validateForm(formData);
    if (validationErrors) {
      setErrors(validationErrors);
      return;
    }
    // Submit form...
  };

  return (
    <form onSubmit={handleSubmit}>
      {Object.entries(formlessRegistry.fields).map(([key, field]) => (
        <div key={key} className="form-group">
          <label htmlFor={key}>
            {field.label}
            {field.required && <span className="required">*</span>}
          </label>
          <input
            type={field.type}
            id={key}
            name={key}
            value={formData[key] || ''}
            onChange={handleChange}
            required={field.required}
            pattern={field.pattern}
            placeholder={field.placeholder}
            className={errors[key] ? 'error' : ''}
          />
          {field.description && (
            <div className="help-text">{field.description}</div>
          )}
          {errors[key] && (
            <div className="error-message">{errors[key]}</div>
          )}
        </div>
      ))}
      <button type="submit">Submit</button>
    </form>
  );
}

Contributing

Contributions are welcome! Please read our Contributing Guide to get started.

License

MIT © [Your Name]

Changelog

0.1.0

  • Initial release of formless-registry
  • Added core field definitions
  • TypeScript support
  • Comprehensive documentation
function validateField(fieldName: string, value: string): boolean {
  const field = formlessRegistry.fields[fieldName as keyof typeof formlessRegistry.fields];
  if (!field) return false;
  
  if (field.required && !value) return false;
  if (field.pattern && !new RegExp(field.pattern).test(value)) return false;
  if (field.minLength && value.length < field.minLength) return false;
  if (field.maxLength && value.length > field.maxLength) return false;
  
  return true;
}

// Example usage
validateField('email', '[email protected]'); // true
validateField('email', 'invalid-email');    // false

Getting Fields by Category

function getFieldsByCategory(category: string) {
  return Object.entries(formlessRegistry.fields)
    .filter(([_, config]) => config.category === category)
    .map(([key, config]) => ({
      key,
      label: config.label,
      type: config.type,
      required: config.required,
    }));
}

// Get all personal information fields
const personalFields = getFieldsByCategory('personal');

Getting Fields by Type

function getFieldsByType(type: FieldType) {
  return Object.entries(formlessRegistry.fields)
    .filter(([_, config]) => config.type === type)
    .map(([key, config]) => ({
      key,
      label: config.label,
      category: config.category,
    }));
}

// Get all select fields
const selectFields = getFieldsByType('select');

API Reference

formlessRegistry

The main registry object containing all field definitions.

Properties

  • version: string - The current version of the registry
  • fields: Record<string, FieldConfig> - Object containing all field definitions
  • categories?: Record<string, CategoryConfig> - Optional categories for organizing fields
  • meta?: Record<string, any> - Additional metadata about the registry

Types

FieldConfig

interface FieldConfig {
  // Basic field information
  type: FieldType;
  label: string;
  description?: string;
  required?: boolean;
  
  // Validation
  pattern?: string;
  patternMessage?: string;
  minLength?: number;
  maxLength?: number;
  min?: number | string;
  max?: number | string;
  
  // Metadata
  category?: string;
  deprecated?: boolean;
  version?: string;
  examples?: any[];
  
  // For select/radio fields
  options?: Array<{
    label: string;
    value: any;
    disabled?: boolean;
  }>;
}

FieldType

type FieldType =
  | 'text'
  | 'email'
  | 'password'
  | 'number'
  | 'tel'
  | 'url'
  | 'date'
  | 'time'
  | 'datetime-local'
  | 'month'
  | 'week'
  | 'color'
  | 'checkbox'
  | 'radio'
  | 'select'
  | 'textarea'
  | 'hidden';

Development

Prerequisites

  • Node.js 16+
  • npm or yarn

Installation

git clone https://github.com/your-org/formless.git
cd formless/packages/registry
npm install

Building

# Build the project
npm run build

# Watch for changes
npm run build -- --watch

Testing

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Generate test coverage
npm run test:coverage

Linting

# Run linter
npm run lint

# Fix linting issues
npm run lint:fix

Contributing

Contributions are welcome! Please read our contributing guide to get started.

License

MIT © Formless Team description?: string; [key: string]: any; }; }


## Field Configuration

Each field in the registry is a `FieldConfig` object with properties like:

```typescript
{
  type: FieldType;  // 'text', 'email', 'password', etc.
  label: string;    // Human-readable label
  description?: string;  // Help text
  required?: boolean;    // Whether the field is required
  default?: any;         // Default value
  // ... and many more
}

Extending the Registry

You can extend the default registry with your own fields:

import { formlessRegistry } from '@formless/registry';

const customRegistry = {
  ...formlessRegistry,
  fields: {
    ...formlessRegistry.fields,
    customField: {
      type: 'text',
      label: 'Custom Field',
      // ...
    }
  }
};

Building

npm install
npm run build

License

MIT