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

@proveanything/smartlinks-form-renderer

v0.2.0

Published

SmartLinks form renderer and editor — render forms from JSON schema or build them with the visual editor

Downloads

95

Readme

SmartLinks Forms

A flexible React package for rendering and editing forms from JSON schema — with conditional logic, validation, table fields, storage configuration, and a visual editor.

Installation

npm install @proveanything/smartlinks-forms

Subpath Imports

// Full package (renderer + editor + types)
import { SchemaFormRenderer, useFormEditorState } from '@proveanything/smartlinks-forms';

// Renderer only (lean, public-facing)
import { SchemaFormRenderer } from '@proveanything/smartlinks-forms/renderer';

// Editor only (admin-facing)
import { useFormEditorState, useFormEditorActions } from '@proveanything/smartlinks-forms/editor';

Form Renderer

Basic Usage

import { SchemaFormRenderer, SchemaFormConfig } from '@proveanything/smartlinks-forms';

const formConfig: SchemaFormConfig = {
  title: "Contact Form",
  description: "Fill in your details",
  schema: {
    type: "object",
    properties: {
      name: { type: "string", title: "Full Name" },
      email: { type: "string", format: "email", title: "Email" },
    },
    required: ["name", "email"]
  },
  uiSchema: {
    name: { "ui:placeholder": "Enter your full name" },
    email: { "ui:placeholder": "[email protected]" },
  },
  storage: { name: "public", email: "private" },
  settings: {
    allowMultipleSubmissions: false,
    requireAuthentication: false,
    showProgressBar: false,
    submitButtonText: "Submit",
    successMessage: "Form submitted successfully!"
  },
  styling: { theme: "default", primaryColor: "#007bff", backgroundColor: "#ffffff" },
  fieldOrder: ["name", "email"]
};

function MyForm() {
  return (
    <SchemaFormRenderer
      config={formConfig}
      onSubmit={(data) => console.log('Submitted:', data)}
      initialData={{ name: "John Doe" }}
    />
  );
}

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | config | SchemaFormConfig | Required | The form configuration object | | onSubmit | (data: Record<string, any>) => void | Required | Called on valid submission | | isSubmitting | boolean | false | Disables submit button | | className | string | "" | Additional CSS classes | | initialData | Record<string, any> | {} | Pre-populate fields (overrides schema defaults) | | components | object | {} | Custom component overrides |


Field Types & Formats

String Fields

  • text (default), email, textarea, select, radio, checkboxes, multiselect, combobox, file, date, date-time

Boolean Fields

  • checkbox (default), switch

Number / Integer Fields

  • Standard number input with minimum/maximum validation

Table Fields

  • Dynamic table with typed columns, row add/remove, minRows/maxRows

Validation

The renderer enforces validation at submit time with inline error messages. Both HTML attributes and JavaScript-level checks are used.

Supported Constraints

| Constraint | Applies To | Description | |------------|-----------|-------------| | required | All types | Field must have a value (set via schema.required[]) | | minLength | string | Minimum character length | | maxLength | string | Maximum character length | | pattern | string | Regex pattern the value must match | | minimum | number, integer | Minimum numeric value | | maximum | number, integer | Maximum numeric value | | minRows | table | Minimum number of table rows | | maxRows | table | Maximum number of table rows |

Example

{
  age: {
    type: "integer",
    title: "Age",
    minimum: 18,
    maximum: 120
  },
  bio: {
    type: "string",
    format: "textarea",
    title: "Bio",
    minLength: 10,
    maxLength: 500
  }
}

Enum Labels (enumNames)

Use enumNames as a parallel array to enum for human-readable labels:

{
  country: {
    type: "string",
    format: "select",
    title: "Country",
    enum: ["us", "gb", "de"],
    enumNames: ["United States", "United Kingdom", "Germany"]
  }
}

enum[i] is the stored value, enumNames[i] is the display label. Works with select, radio, checkboxes, multiselect, and combobox formats.


UI Schema

Control presentation without changing the data schema:

uiSchema: {
  bio: {
    "ui:placeholder": "Tell us about yourself...",
    "ui:help": "This will be shown on your profile",
    "ui:options": { rows: 6 },
    "ui:disabled": true  // Read-only field
  },
  avatar: {
    "ui:options": { accept: "image/*" }
  }
}

Available UI Properties

| Property | Type | Description | |----------|------|-------------| | ui:placeholder | string | Placeholder text | | ui:help | string | Help text below the field | | ui:disabled | boolean | Disables the field (read-only) | | ui:widget | string | Override auto-detected widget | | ui:options.rows | number | Textarea row count | | ui:options.accept | string | File input accept filter | | ui:options.label | boolean | Show/hide label |


Conditional Logic

Show/hide fields based on other field values:

{
  preferences: {
    type: "string",
    format: "select",
    title: "Preferences",
    enum: ["daily", "weekly"],
    conditions: [
      { targetFieldId: "subscribe", operator: "equals", value: true }
    ],
    showWhen: "all" // or "any"
  }
}

Operators

| Operator | Description | Needs value? | |----------|-------------|---------------| | equals | Strict equality | Yes | | not_equals | Not equal | Yes | | contains | String contains | Yes | | not_contains | String doesn't contain | Yes | | greater_than | Numeric comparison | Yes | | less_than | Numeric comparison | Yes | | is_empty | Value is empty/null | No | | is_not_empty | Value has content | No | | is_true | Value is true | No | | is_false | Value is false/null/undefined | No |


Field Ordering

const config: SchemaFormConfig = {
  fieldOrder: ["name", "email", "phone", "address"],
  // ...
};

If fieldOrder is not specified, fields appear in schema.properties insertion order.


Table Fields

{
  items: {
    type: "table",
    title: "Line Items",
    columns: [
      { id: "name", title: "Item", type: "string", required: true },
      { id: "qty", title: "Quantity", type: "number", required: true },
      { id: "active", title: "Active", type: "boolean" },
      { id: "date", title: "Added", type: "date" }
    ],
    minRows: 1,
    maxRows: 10
  }
}

Custom Components

Override default UI primitives:

<SchemaFormRenderer
  config={formConfig}
  onSubmit={handleSubmit}
  components={{
    Button: MyButton,
    Input: MyInput,
    Textarea: MyTextarea,
    Select: MySelect,
    Checkbox: MyCheckbox,
    RadioGroup: MyRadioGroup,
    Switch: MySwitch,
    Label: MyLabel,
    TableInput: MyTableInput,
  }}
/>

Storage Configuration

Define privacy levels per field:

storage: {
  name: "public",     // Publicly visible
  email: "private",   // Private to user
  ssn: "proof",       // Cryptographic proof only
  notes: "personal"   // Personal notes
}

Form Editor (Admin)

The editor hooks provide headless state management for building a form editor UI:

import { useFormEditorState, useFormEditorActions } from '@proveanything/smartlinks-forms/editor';

function FormEditor() {
  const editor = useFormEditorState({ isCreating: true });
  const actions = useFormEditorActions({
    formConfig: editor.formConfig,
    setFormConfig: editor.setFormConfig,
  });

  // editor.addField(), editor.updateField(), editor.removeField(), etc.
  // actions.exportSchema(), actions.importSchema()
}

Configuration Reference

SchemaFormConfig

| Property | Type | Description | |----------|------|-------------| | id | string? | Unique identifier | | title | string | Form title | | description | string | Form description | | schema | object | JSON Schema definition | | uiSchema | object | UI configuration | | storage | object | Per-field storage levels | | settings | object | Form behavior settings | | styling | object | Theme and colours | | fieldOrder | string[]? | Field display order |


TypeScript

import type {
  SchemaFormConfig,
  SchemaFormField,
  SchemaFormRendererProps,
  SchemaFormUIConfig,
  SchemaFormFieldCondition,
  TableColumn,
  FormEditorState,
  FormEditorActions,
} from '@proveanything/smartlinks-forms';

License

MIT