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

@algodomain/smart-forms

v0.1.7

Published

A powerful React form framework with smart fields, multi-tab support, and seamless API integration

Downloads

727

Readme

@algodomain/smart-forms

A powerful, flexible React form framework with smart fields, multi-tab support, built-in validation, and seamless API integration.

npm version License: MIT

Built with TypeScript, Tailwind CSS, Zod validation, and shadcn/ui components.


📋 Table of Contents


✨ Features

  • 🎯 Smart Fields - Pre-built, validated form fields with consistent UX
  • 📑 Multi-Tab Forms - Create complex forms with tabbed navigation and progress tracking
  • Built-in Validation - Powered by Zod for type-safe validation
  • 🔄 API Integration - Automatic form submission with authentication support
  • 🔗 Query Params - Include URL query parameters in form submissions
  • 💾 Auto-Save - LocalStorage support for draft saving
  • 🎛️ Conditional Disabling - Disable fields and submit buttons based on form data
  • 🎨 Customizable - Full theme control via CSS variables
  • 🌙 Dark Mode - Built-in support for light and dark themes
  • Accessible - Built on Radix UI primitives
  • 📦 Tree-Shakeable - Import only what you need
  • 🔒 Type-Safe - Full TypeScript support

📦 Installation

1. Install the Package

npm install @algodomain/smart-forms
# or
yarn add @algodomain/smart-forms
# or
pnpm add @algodomain/smart-forms

2. Install Peer Dependencies

npm install react react-dom tailwindcss zod react-toastify date-fns lucide-react

3. Import Styles

Add to your main entry file (main.tsx or index.tsx):

import '@algodomain/smart-forms/style.css'
import 'react-toastify/dist/ReactToastify.css'

4. Configure Tailwind CSS (v4)

Add @source directives to scan the package for Tailwind classes:

/* src/index.css */
@import "tailwindcss";

@source "../node_modules/@algodomain/smart-forms/dist/index.js";
@source "../node_modules/@algodomain/smart-forms/dist/index.cjs";

@import "@algodomain/smart-forms/style.css";

🚀 Quick Start

Basic Form Example

import { SmartForm } from '@algodomain/smart-forms'
import { SmartInput, SmartSelect } from '@algodomain/smart-forms/fields'
import { FieldEmail } from '@algodomain/smart-forms/opinionated'
import { z } from 'zod'

function RegistrationForm() {
  return (
    <SmartForm
      api="https://api.example.com/register"
      method="POST"
      submitButtonText="Sign Up"
      onSuccess={(data) => console.log('Success!', data)}
      onError={(error) => console.error('Error:', error)}
    >
      <SmartInput
        field="name"
        label="Full Name"
        validation={z.string().min(3, 'Name must be at least 3 characters')}
        required
      />
      
      <FieldEmail field="email" required />
      
      <SmartSelect
        field="role"
        label="Role"
        options={[
          { value: 'user', label: 'User' },
          { value: 'admin', label: 'Admin' }
        ]}
        required
      />
    </SmartForm>
  )
}

Multi-Tab Form Example

import { MultiTabSmartForm, Tab } from '@algodomain/smart-forms'
import { SmartInput, SmartTags } from '@algodomain/smart-forms/fields'
import { z } from 'zod'

function JobPostingForm() {
  return (
    <MultiTabSmartForm
      api="/api/jobs"
      method="POST"
      showProgressBar={true}
      showTabNumbers={true}
      onSuccess={(data) => console.log('Job created:', data)}
    >
      <Tab title="Basic Info">
        <SmartInput 
          field="jobTitle" 
          label="Job Title" 
          validation={z.string().min(3)}
          required 
        />
      </Tab>
      
      <Tab title="Requirements">
        <SmartTags 
          field="skills" 
          label="Required Skills"
          validation={z.array(z.string()).min(1)}
          required 
        />
      </Tab>
    </MultiTabSmartForm>
  )
}

📝 Form Components

SmartForm

Single-page form with automatic submission handling.

Usage:

<SmartForm
  api="/api/endpoint"
  method="POST"
  onSuccess={(data) => console.log(data)}
  onError={(error) => console.error(error)}
>
  {/* Your fields here */}
</SmartForm>

MultiTabSmartForm

Multi-step form with tabs and progress tracking.

Usage:

<MultiTabSmartForm
  api="/api/submit"
  showProgressBar={true}
  showTabNumbers={true}
>
  <Tab title="Step 1">
    {/* Fields */}
  </Tab>
  <Tab title="Step 2">
    {/* Fields */}
  </Tab>
</MultiTabSmartForm>

BaseSmartForm

Low-level form component for custom layouts.

Usage:

<BaseSmartForm api="/api/submit">
  <div className="custom-layout">
    <SmartInput field="name" label="Name" />
    <CustomSubmitButton />
  </div>
</BaseSmartForm>

🎯 Field Components

All field components are imported from @algodomain/smart-forms/fields:

import {
  SmartInput,
  SmartSelect,
  SmartCheckbox,
  SmartRadioGroup,
  SmartDatePicker,
  SmartTags,
  SmartSlider,
  SmartDualRangeSlider,
  SmartCombobox,
  SmartBasicRichTextbox,
  SmartFileUpload,
  SmartAutoSuggestTags
} from '@algodomain/smart-forms/fields'

SmartInput

Text input with support for multiple types.

<SmartInput
  field="username"
  label="Username"
  type="text"
  placeholder="Enter username"
  validation={z.string().min(3).max(20)}
  required
/>

Supported types: text, email, password, tel, number, textarea

SmartSelect

Dropdown select field.

<SmartSelect
  field="country"
  label="Country"
  options={[
    { value: 'us', label: 'United States' },
    { value: 'ca', label: 'Canada' }
  ]}
  required
/>

SmartCheckbox

Checkbox with label.

<SmartCheckbox
  field="terms"
  label="I agree to terms"
  validation={z.boolean().refine(val => val === true)}
  required
/>

SmartRadioGroup

Radio button group.

<SmartRadioGroup
  field="gender"
  label="Gender"
  options={[
    { value: 'male', label: 'Male' },
    { value: 'female', label: 'Female' }
  ]}
  alignment="horizontal"
  required
/>

SmartDatePicker

Date picker with calendar UI.

<SmartDatePicker
  field="birthDate"
  label="Date of Birth"
  validation={z.date()}
  required
/>

SmartTags

Tag input for multiple values.

<SmartTags
  field="skills"
  label="Skills"
  placeholder="Type and press Enter"
  validation={z.array(z.string()).min(1)}
  maxTags={10}
  required
/>

SmartSlider

Single value slider.

<SmartSlider
  field="experience"
  label="Years of Experience"
  min={0}
  max={40}
  step={1}
  showValue={true}
/>

SmartDualRangeSlider

Min/max range slider.

<SmartDualRangeSlider
  minField="minSalary"
  maxField="maxSalary"
  label="Salary Range"
  min={0}
  max={200000}
  step={5000}
/>

SmartCombobox

Searchable combo box.

<SmartCombobox
  field="technology"
  label="Technology"
  options={[
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue' }
  ]}
  allowCustom={true}
/>

SmartBasicRichTextbox

Basic rich text editor.

<SmartBasicRichTextbox
  field="description"
  label="Description"
  minHeight="150px"
  validation={z.string().min(50)}
  required
/>

SmartFileUpload

File upload field.

<SmartFileUpload
  field="resume"
  label="Upload Resume"
  accept=".pdf,.doc,.docx"
  maxSize={5 * 1024 * 1024}
  required
/>

🎨 Opinionated Fields

Pre-configured fields with built-in validation. Import from @algodomain/smart-forms/opinionated:

import {
  FieldEmail,
  FieldPassword,
  FieldConfirmPassword,
  FieldPhone,
  FieldFirstName,
  FieldLastName,
  FieldFullName,
  FieldAge,
  FieldStreetAddress,
  FieldCity,
  FieldState,
  FieldZipCode,
  FieldMessage,
  FieldComments
} from '@algodomain/smart-forms/opinionated'

Usage:

<FieldEmail field="email" required />
<FieldPassword field="password" required />
<FieldPhone field="phone" />
<FieldFullName field="fullName" required />

⚙️ Configuration Reference

Form Component Props

All form components (SmartForm, MultiTabSmartForm, BaseSmartForm) support these props:

| Prop | Type | Default | Description | |------|------|---------|-------------| | api | string | - | API endpoint for form submission | | method | 'POST' \| 'PUT' \| 'PATCH' | 'POST' | HTTP method | | submitButtonText | string | 'Submit' | Submit button text | | submitButtonIcon | ReactNode | - | Icon for submit button | | allowSaveDraft | boolean | false | Enable draft saving | | saveDraftApi | string | - | API endpoint for saving drafts | | enableLocalStorage | boolean | false | Save drafts to localStorage | | storageKey | string | 'smart-form-data' | Key for localStorage | | logFormData | boolean | false | Log form data to console | | onSuccess | (data: unknown) => void | - | Success callback | | onError | (error: unknown) => void | - | Error callback | | transformData | (data: any) => any | - | Transform data before submission | | className | string | 'max-w-2xl mx-auto p-6 bg-white' | Container CSS class | | title | string | - | Form title | | subTitle | string | - | Form subtitle | | logo | ReactNode | - | Logo to display | | footer | ReactNode | - | Footer content | | initialData | Record<string, unknown> | {} | Initial form values | | showReset | boolean | false | Show reset button | | showProgressBar | boolean | true | Display progress bar (MultiTab only) | | showTabNumbers | boolean | true | Show tab numbers (MultiTab only) | | authentication | AuthenticationConfig | - | Authentication configuration | | includeQueryParams | boolean | false | Include URL query parameters | | queryParamsToInclude | string[] | - | Filter specific query params | | submitDisabled | boolean \| ((formData: any) => boolean) | false | Disable submit button statically or conditionally based on form data | | children | ReactNode | - | Form content |

Authentication Configuration

interface AuthenticationConfig {
  enable: boolean                    // Enable authentication
  refreshTokenEndpoint?: string      // Token refresh endpoint
  accessTokenKey?: string            // localStorage key (default: 'accessToken')
  refreshTokenKey?: string           // localStorage key (default: 'refreshToken')
}

Usage:

<SmartForm
  authentication={{
    enable: true,
    refreshTokenEndpoint: "/api/auth/refresh",
    accessTokenKey: "accessToken",
    refreshTokenKey: "refreshToken"
  }}
>
  {/* Fields */}
</SmartForm>

Common Field Props

All field components support these props:

| Prop | Type | Default | Description | |------|------|---------|-------------| | field | string | - | Required. Field identifier | | label | string | - | Field label | | required | boolean | false | Mark as required | | validation | ZodSchema | - | Zod validation schema | | defaultValue | any | - | Initial value | | placeholder | string | - | Placeholder text | | className | string | - | Custom CSS class | | info | string | - | Info tooltip text | | subLabel | string | - | Additional helper text | | disabled | boolean \| ((formData: any) => boolean) | false | Disable field statically or conditionally based on form data | | hidden | boolean \| ((formData: any) => boolean) | false | Hide field conditionally based on form data |

Field-Specific Props

SmartInput

| Prop | Type | Default | Allowed Values | |------|------|---------|----------------| | type | string | 'text' | text, email, password, tel, number, textarea |

SmartSelect / SmartCombobox

| Prop | Type | Default | Description | |------|------|---------|-------------| | options | Array<{value: string, label: string}> | [] | Select options | | allowCustom | boolean | false | Allow custom values (Combobox only) |

SmartRadioGroup

| Prop | Type | Default | Allowed Values | |------|------|---------|----------------| | options | Array<{value: string, label: string}> | [] | Radio options | | alignment | string | 'vertical' | horizontal, vertical |

SmartTags

| Prop | Type | Default | Description | |------|------|---------|-------------| | maxTags | number | - | Maximum number of tags | | maxLength | number | - | Max length per tag | | minLength | number | - | Min length per tag | | allowDuplicates | boolean | true | Allow duplicate tags |

SmartSlider

| Prop | Type | Default | Description | |------|------|---------|-------------| | min | number | 0 | Minimum value | | max | number | 100 | Maximum value | | step | number | 1 | Step increment | | showValue | boolean | true | Display current value | | valueFormatter | (value: number) => string | - | Format displayed value |

SmartDualRangeSlider

| Prop | Type | Default | Description | |------|------|---------|-------------| | minField | string | - | Required. Field name for min value | | maxField | string | - | Required. Field name for max value | | min | number | 0 | Minimum value | | max | number | 100 | Maximum value | | step | number | 1 | Step increment | | showValues | boolean | true | Display values | | valueFormatter | (value: number) => string | - | Format displayed value |

SmartBasicRichTextbox

| Prop | Type | Default | Description | |------|------|---------|-------------| | minHeight | string | '150px' | Minimum height | | maxHeight | string | '400px' | Maximum height |

SmartFileUpload

| Prop | Type | Default | Description | |------|------|---------|-------------| | accept | string | - | Accepted file types | | maxSize | number | - | Max file size in bytes |


🚀 Advanced Features

Conditional Field Disabling

Disable fields or submit buttons based on form data values. Supports both static boolean values and dynamic functions.

Disable Fields Conditionally

Static Disable:

<SmartInput
  field="username"
  label="Username"
  disabled={true}
/>

Conditional Disable Based on Form Data:

<SmartForm api="/api/submit">
  <SmartCombobox
    field="country"
    label="Country"
    options={[
      { value: 'us', label: 'United States' },
      { value: 'ca', label: 'Canada' }
    ]}
    placeholder="Please select the country"
  />
  
  <SmartCombobox
    field="state"
    label="State"
    options={stateOptions}
    disabled={(formData) => !formData.country || formData.country === ""}
  />
  
  <SmartInput
    field="zipCode"
    label="Zip Code"
    disabled={(formData) => !formData.state}
  />
</SmartForm>

How it works:

  • The disabled function receives the current formData object
  • It re-evaluates automatically when form data changes
  • Returns true to disable, false to enable
  • Empty strings, null, and undefined are all falsy in JavaScript

Example: Disable until checkbox is checked:

<SmartForm api="/api/submit">
  <SmartCheckbox
    field="agreeToTerms"
    label="I agree to the terms and conditions"
  />
  
  <SmartInput
    field="comments"
    label="Additional Comments"
    disabled={(formData) => !formData.agreeToTerms}
  />
</SmartForm>

Example: Complex conditional logic:

<SmartInput
  field="phone"
  label="Phone Number"
  disabled={(formData) => {
    // Disable if email is not provided OR if user is under 18
    return !formData.email || (formData.age && formData.age < 18)
  }}
/>

Disable Submit Button Conditionally

Static Disable:

<SmartForm
  api="/api/submit"
  submitDisabled={true}
>
  {/* Fields */}
</SmartForm>

Conditional Disable:

<SmartForm
  api="/api/submit"
  submitDisabled={(formData) => !formData.agreeToTerms}
>
  <SmartInput field="name" label="Name" required />
  <SmartCheckbox
    field="agreeToTerms"
    label="I agree to the terms"
  />
</SmartForm>

Example: Disable submit until all required fields are filled:

<SmartForm
  api="/api/submit"
  submitDisabled={(formData) => {
    return !formData.name || !formData.email || !formData.agreeToTerms
  }}
>
  <SmartInput field="name" label="Name" required />
  <SmartInput field="email" label="Email" required />
  <SmartCheckbox field="agreeToTerms" label="I agree" required />
</SmartForm>

Note: The submit button is automatically disabled when isLoading is true. The submitDisabled prop is combined with the loading state: disabled={isLoading || isSubmitDisabled}.

Combining Disabled and Hidden

You can use both disabled and hidden together for different scenarios:

<SmartForm api="/api/submit">
  <SmartSelect
    field="userType"
    label="User Type"
    options={[
      { value: 'admin', label: 'Admin' },
      { value: 'user', label: 'User' }
    ]}
  />
  
  {/* Hidden for non-admin users */}
  <SmartInput
    field="adminCode"
    label="Admin Code"
    hidden={(formData) => formData.userType !== 'admin'}
  />
  
  {/* Disabled (but visible) for admin users */}
  <SmartInput
    field="userNotes"
    label="User Notes"
    disabled={(formData) => formData.userType === 'admin'}
  />
</SmartForm>

Hide Fields Conditionally

Hide fields completely from the form based on form data. When a field is hidden, it's not rendered at all (unlike disabled which shows the field but makes it non-interactive).

Static Hide:

<SmartInput
  field="optionalField"
  label="Optional Field"
  hidden={true}
/>

Conditional Hide:

<SmartForm api="/api/submit">
  <SmartSelect
    field="accountType"
    label="Account Type"
    options={[
      { value: 'personal', label: 'Personal' },
      { value: 'business', label: 'Business' }
    ]}
  />
  
  {/* Only show business fields when account type is business */}
  <SmartInput
    field="businessName"
    label="Business Name"
    hidden={(formData) => formData.accountType !== 'business'}
  />
  
  <SmartInput
    field="taxId"
    label="Tax ID"
    hidden={(formData) => formData.accountType !== 'business'}
  />
</SmartForm>

Example: Show/hide based on checkbox:

<SmartForm api="/api/submit">
  <SmartCheckbox
    field="hasSpecialRequirements"
    label="I have special requirements"
  />
  
  <SmartInput
    field="specialRequirements"
    label="Please describe your requirements"
    type="textarea"
    hidden={(formData) => !formData.hasSpecialRequirements}
  />
</SmartForm>

Difference between disabled and hidden:

  • disabled: Field is visible but grayed out and non-interactive
  • hidden: Field is completely removed from the DOM (not rendered)

When to use each:

  • Use disabled when you want to show the field exists but is temporarily unavailable
  • Use hidden when you want to completely hide fields that aren't relevant to the current form state

All Supported Components

Both disabled and hidden props are available on all smart field components:

  • SmartInput
  • SmartSelect
  • SmartCombobox
  • SmartCheckbox
  • SmartRadioGroup
  • SmartDatePicker
  • SmartSlider
  • SmartDualRangeSlider
  • SmartTags
  • SmartFileUpload
  • SmartAutoSuggestTags
  • SmartBasicRichTextbox

Query Parameters

Automatically include URL query parameters in form submissions.

Include ALL query parameters:

<SmartForm
  api="/api/submit"
  includeQueryParams={true}
>
  <SmartInput field="name" label="Name" />
</SmartForm>

Include SPECIFIC query parameters:

<SmartForm
  api="/api/submit"
  includeQueryParams={true}
  queryParamsToInclude={['userId', 'companyId']}
>
  <SmartInput field="name" label="Name" />
</SmartForm>

Example:

  • URL: /form?userId=123&companyId=456
  • Form data: { name: "John" }
  • Submitted: { userId: "123", companyId: "456", name: "John" }

Behavior:

  • Form field values always override query params if names conflict
  • Works with both form submission and draft saving
  • If queryParamsToInclude is omitted, all query params are included

Draft Saving

Local Storage:

<SmartForm
  enableLocalStorage={true}
  storageKey="my-form-draft"
  allowSaveDraft={true}
>
  {/* Fields */}
</SmartForm>

API-based Draft:

<SmartForm
  allowSaveDraft={true}
  saveDraftApi="/api/drafts"
>
  {/* Fields */}
</SmartForm>

Data Transformation

Transform form data before submission:

<SmartForm
  transformData={(data) => ({
    ...data,
    skills: data.skills?.join(','),
    timestamp: new Date().toISOString()
  })}
>
  {/* Fields */}
</SmartForm>

Initial Values

Pre-populate form fields:

<SmartForm
  initialData={{
    name: 'John Doe',
    email: '[email protected]',
    country: 'us'
  }}
>
  {/* Fields */}
</SmartForm>

Authentication

Enable automatic Bearer token authentication:

<SmartForm
  authentication={{
    enable: true,
    refreshTokenEndpoint: "/api/auth/refresh"
  }}
>
  {/* Fields */}
</SmartForm>

The library will:

  1. Get access token from localStorage
  2. Include it as Authorization: Bearer <token>
  3. Automatically refresh if token expires
  4. Retry the request with new token

🎨 Theming & Customization

CSS Variables

Override the default theme by defining CSS variables:

:root {
  --radius: 0.5rem;
  --background: white;
  --foreground: black;
  --primary: #3b82f6;
  --primary-foreground: white;
  --border: #e5e7eb;
  --input: #e5e7eb;
  --ring: #3b82f6;
}

.dark {
  --background: #1f2937;
  --foreground: white;
  --primary: #60a5fa;
}

Tailwind Classes

Customize using Tailwind utility classes:

<SmartForm className="max-w-4xl mx-auto p-8 bg-gray-50 rounded-xl shadow-lg">
  <SmartInput
    field="name"
    label="Name"
    className="border-blue-500 focus:ring-blue-500"
  />
</SmartForm>

Custom Submit Button

Use BaseSmartForm with custom buttons:

import { BaseSmartForm, useSmartForm } from '@algodomain/smart-forms'

function CustomForm() {
  return (
    <BaseSmartForm api="/api/submit">
      <SmartInput field="name" label="Name" />
      <CustomSubmitButton />
    </BaseSmartForm>
  )
}

function CustomSubmitButton() {
  const { submitForm, isLoading } = useSmartForm()
  
  return (
    <button onClick={submitForm} disabled={isLoading}>
      {isLoading ? 'Submitting...' : 'Submit'}
    </button>
  )
}

🪝 Hooks & Context

useSmartForm

Access form context and methods.

import { useSmartForm } from '@algodomain/smart-forms'

function MyComponent() {
  const {
    formData,        // Current form values
    errors,          // Validation errors
    isLoading,       // Submission loading state
    isDraftSaving,   // Draft saving state
    submitForm,      // Submit function
    saveDraft,       // Save draft function
    resetForm,       // Reset to initial values
    updateField,     // Update specific field
    config           // Form configuration
  } = useSmartForm()
  
  return <button onClick={submitForm}>Submit</button>
}

useFormField

Access individual field state (used internally by field components).

import { useFormField } from '@algodomain/smart-forms'

function CustomField({ field }) {
  const { value, error, onChange } = useFormField(field)
  
  return (
    <input
      value={value || ''}
      onChange={(e) => onChange(e.target.value)}
    />
  )
}

💡 Examples

Complete Registration Form

import { SmartForm } from '@algodomain/smart-forms'
import { SmartInput, SmartSelect, SmartCheckbox, SmartDatePicker } from '@algodomain/smart-forms/fields'
import { FieldEmail, FieldPassword } from '@algodomain/smart-forms/opinionated'
import { z } from 'zod'
import { toast } from 'react-toastify'

export function RegistrationForm() {
  return (
    <SmartForm
      api="https://api.example.com/register"
      method="POST"
      submitButtonText="Register"
      submitDisabled={(formData) => !formData.agreeToTerms}
      onSuccess={(data) => {
        toast.success('Account created successfully!')
      }}
      onError={(error) => {
        toast.error('Registration failed.')
      }}
    >
      <SmartInput
        field="fullName"
        label="Full Name"
        validation={z.string().min(3)}
        required
      />
      
      <FieldEmail field="email" required />
      <FieldPassword field="password" required />
      
      <SmartSelect
        field="country"
        label="Country"
        options={[
          { value: 'us', label: 'United States' },
          { value: 'ca', label: 'Canada' },
          { value: 'uk', label: 'United Kingdom' }
        ]}
        required
      />
      
      <SmartSelect
        field="state"
        label="State"
        options={stateOptions}
        disabled={(formData) => !formData.country}
      />
      
      <SmartDatePicker
        field="birthDate"
        label="Date of Birth"
        validation={z.date().max(new Date())}
        required
      />
      
      <SmartCheckbox
        field="terms"
        label="I agree to the Terms and Conditions"
        validation={z.boolean().refine(val => val === true)}
        required
      />
    </SmartForm>
  )
}

Multi-Tab Job Application

import { MultiTabSmartForm, Tab } from '@algodomain/smart-forms'
import { SmartInput, SmartTags, SmartDualRangeSlider } from '@algodomain/smart-forms/fields'
import { FieldEmail, FieldPhone } from '@algodomain/smart-forms/opinionated'
import { z } from 'zod'

export function JobApplicationForm() {
  return (
    <MultiTabSmartForm
      api="/api/applications"
      method="POST"
      showProgressBar={true}
      showTabNumbers={true}
      allowSaveDraft={true}
      enableLocalStorage={true}
      storageKey="job-application"
    >
      <Tab title="Personal Info">
        <SmartInput
          field="fullName"
          label="Full Name"
          validation={z.string().min(3)}
          required
        />
        <FieldEmail field="email" required />
        <FieldPhone field="phone" required />
      </Tab>
      
      <Tab title="Experience">
        <SmartDualRangeSlider
          minField="minExperience"
          maxField="maxExperience"
          label="Years of Experience"
          min={0}
          max={40}
          step={1}
        />
        <SmartTags
          field="skills"
          label="Skills"
          validation={z.array(z.string()).min(3)}
          required
        />
      </Tab>
    </MultiTabSmartForm>
  )
}

Form with Query Parameters

// URL: /create-job?userId=123&companyId=456

<SmartForm
  api="/api/jobs"
  includeQueryParams={true}
  queryParamsToInclude={['userId', 'companyId']}
>
  <SmartInput field="jobTitle" label="Job Title" required />
  <SmartInput field="location" label="Location" required />
</SmartForm>

// Submitted data will include:
// { userId: "123", companyId: "456", jobTitle: "...", location: "..." }

🐛 Troubleshooting

Error: "useSmartForm must be used within a SmartFormProvider"

Cause: Field components used outside a form wrapper.

Solution: Wrap fields in a form component:

// ❌ Wrong
<SmartInput field="name" label="Name" />

// ✅ Correct
<SmartForm api="/api/submit">
  <SmartInput field="name" label="Name" />
</SmartForm>

Styles Not Loading

Cause: CSS not imported.

Solution:

import '@algodomain/smart-forms/style.css'
import 'react-toastify/dist/ReactToastify.css'

For Tailwind v4, add @source directives:

@source "../node_modules/@algodomain/smart-forms/dist/index.js";

Form Not Submitting

Cause: Missing API endpoint or validation errors.

Solution:

  1. Ensure api prop is set
  2. Check console for validation errors
  3. Use logFormData={true}:
<SmartForm api="/api/submit" logFormData={true}>
  {/* Fields */}
</SmartForm>

TypeScript Errors

Solution: Install type definitions:

npm install @types/react @types/react-dom

📖 Validation with Zod

All fields support Zod schemas for validation:

import { z } from 'zod'

// String validation
validation={z.string().min(3, "Too short").max(50, "Too long")}

// Email
validation={z.string().email("Invalid email")}

// Number
validation={z.number().min(0).max(100)}

// Array
validation={z.array(z.string()).min(1, "Required")}

// Date
validation={z.date().max(new Date(), "Cannot be future")}

// Boolean
validation={z.boolean().refine(val => val === true, {
  message: "Must be true"
})}

// Enum
validation={z.enum(['option1', 'option2'])}

// Custom
validation={z.string().refine(val => val.includes('@'), {
  message: "Must contain @"
})}

🤝 Contributing

Contributions welcome! Please visit our GitHub repository.

📄 License

MIT License - feel free to use in your projects!

🙋 Support


Built with ❤️ by AlgoDomain