Skip to content

Create a custom input

If you want to create a custom input you need to create it using this template and then register it through register helper:

import React from 'react'
import type z from 'zod/v4'
 
// Import your types from library
import { type CommonField, type PropsField } from 'formidabuild'
// Or import internal component like Input as well
import { Input, cn, type CommonField, type PropsField } from 'formidabuild'
 
// Define your custom input value type with this naming convention: `I${COMPONENT-NAME}Value`
export type ICustomInputValue = string
 
// Define your custom input field type with this naming convention: `I${COMPONENT-NAME}Field`
export interface ICustomInputField extends CommonField {
  // Define the type of your custom input
  type: 'custom-input'
  // Define options for your custom input
  options?: {
    placeholder?: string
  }
  // Define validation schema for your custom input
  validation?: z.ZodType<ICustomInputValue>
}
 
// Create your custom input component
const CustomInputField = ({
  id,
  value,
  error,
  disabled,
  options,
  onChange
  // Define the props using PropsField with your custom value and field types
}: PropsField<ICustomInputValue, ICustomInputField>) => {
  return (
    <>
      <!-- YOUR CODE -->
      <!-- when you data change just call onChange -->
    </>
  )
}
 
export default CustomInputField

Example of custom input

import React from 'react'
import type z from 'zod/v4'
import { Input, cn, type CommonField, type PropsField } from 'formidabuild'
 
export type ICustomInputValue = string
export interface ICustomInputField extends CommonField {
  type: 'custom-input'
  options?: {
    placeholder?: string
  }
  validation?: z.ZodType<ICustomInputValue>
}
 
const CustomInputField = ({
  id,
  value,
  error,
  disabled,
  options,
  onChange
}: PropsField<ICustomInputValue, ICustomInputField>) => {
  return (
    <Input
      id={id}
      type="text"
      placeholder={options?.placeholder || ''}
      className={cn(error && !error.valid && 'border-red-500', 'bg-green-500')}
      disabled={disabled}
      value={value}
      onChange={(e) => onChange(e.target.value)}
    />
  )
}
 
export default CustomInputField

Register your custom input

To register your custom input, you need to import it in your _app.tsx file and register it using the componentRegistry.register method.

import React from 'react'
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import CustomInput from '@/components/formidabuild/custom-input'
import { componentRegistry } from 'formidabuild'
 
componentRegistry.register('custom-input', CustomInput) 
 
export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

And declare the module 'formidabuild' and register all the types in your types/formidabuild.ts file

import type { Field, SectionHeader } from 'formidabuild'
import type { ICustomInputField } from '@/components/formidabuild/custom-input'
 
declare module 'formidabuild' { 
  interface CustomFields { 
    'custom-input': ICustomInputField
  } 
} 
 
type ExtendedField = Field | ICustomInputField
 
export type ExtendedForm = Array<{ 
  header?: SectionHeader
  fields: ExtendedField[][] 
}> 

Use your custom input in a form

If you has registered your custom input correctly, you can use it in your form using ExtendedForm instead of Form type.

'use client'
 
import React, { useState } from 'react'
import z from 'zod/v4'
import { type FormValue, Formidabuild } from 'formidabuild'
import type { ExtendedForm } from '@/types/formidabuild'
 
const form = [
  {
    fields: [
      [
        { 
          type: 'custom-input', 
          name: 'customText', 
          options: { 
            placeholder: 'Custom input'
          }, 
          validation: z 
            .string() 
            .min(3, 'Text is required') 
            .max(100, 'Text must be less than 100 characters') 
        } 
      ]
    ]
  }
] as const satisfies ExtendedForm
 
const data: FormValue<typeof form> = { 
  text: '',
  customText: ''
}