turiy-form
v2.3.5
Published
This package is built on shadcn, zod
Maintainers
Readme
Turiy Form Package
This package is made on react, react-dom, zod,tailwindcss, shadcn, radix-ui and react-hook-form.
This is actually help to create a form with validator.
Recommended to use inside
react components.
Create your own FormxField and send it to Formx
//Example given for NextJS
"use client";
import React from "react";
import { Formx, FormxField, regex, equal, Button } from "turiy-form";
import { useToast } from "@/hooks/use-toast"; //toast from shadcn
const signupDefaultValue = {
email: "",
password: "",
cpassword: "",
uname: "",
gender: "",
mob: "",
};
const SignupForm = () => {
const [busy, setBusy] = React.useState(false);
function onSubmit(values: any) {
if (equal(signupDefaultValue, values)) {
toast({
title: "😎 No change!",
description: " You have not made any changes.",
variant: "destructive",
});
return;
}
setBusy(true);
//Todo: do your stuffs here
setBusy(false);
}
return (
<Formx
className="grid grid-cols-1 gap-4 text-slate-950"
onSubmit={onSubmit}
submitButton={
<Button type="submit" className="mx-auto px-8">
Send reset link
</Button>
}
refine={{
//Compare on form fields
on: (data: any) => data.password === data.cpassword,
//Error message if above is false
message: "Please confirm your password",
//Field name where message will be shown
path: ["cpassword"],
}}
>
<FormxField
name="email"
label="Email"
placeholder="[email protected]"
type="email"
required
match={regex.email}
defaultValue=""
/>
<FormxField
name="password"
label="Password"
placeholder="Password like $hRk25!n"
type="password"
required
match={regex.password}
defaultValue=""
/>
<FormxField
name="cpassword"
label="Confirm Password"
placeholder="Type the password again"
type="password"
required
match={regex.password}
defaultValue=""
}
/>
<FormxField
name="uname"
label="Your name"
placeholder="Write your name"
type="text"
required
match={{ type: "string", min: 3 }}
defaultValue=""
/>
<FormxField
name="gender"
label="Gender"
placeholder="Gender"
type="select"
required
defaultValue=""
selectProps={{
options: [
{ label: "Male", value: "1" },
{ label: "Female", value: "2" },
{ label: "Other", value: "3" },
],
}}
/>
<FormxField
name="mob"
label="Mobile no."
placeholder="+91XXXXXXXXXX"
type="tel"
required
match={regex.mobile}
defaultValue=""
/>
</Formx>
);
};
export default SignupForm;Formx - A Declarative Form Library for React
Formx is a powerful, declarative form library for React that simplifies form creation, validation, and state management. By leveraging the robustness of react-hook-form and the type-safety of zod, Formx allows you to build complex forms with minimal boilerplate. Simply define your fields, and Formx handles the rest.
Built with a modern stack including tailwindcss and shadcn/ui for styling, it's designed to be both highly functional and aesthetically pleasing out of the box.
Core Concepts
Formx follows a declarative "container-presenter" pattern:
<Formx>(The Container): This is the main component that orchestrates everything. It reads the configuration from its children, dynamically generates azodvalidation schema, manages the form's state usingreact-hook-form, and handles submissions.<FormxField>(The Declarative API): This component doesn't render any UI itself. Instead, it acts as a "marker" or a configuration object. You use it to define the properties of each form field, such as its name, label, type, and validation rules.<Formx>then uses this information to render the appropriate input (<FormxInput>or<FormxSelect>).
This approach keeps your form definitions clean, readable, and centralized.
Installation
npm install turiy-formor if you use yarn:
yarn add turiy-formNote: Formx relies on peer dependencies like
react,react-hook-form,zod, andtailwindcss. Ensure these are correctly set up in your project.
Quick Start
Let's create a simple login form. This example demonstrates the basic usage of <Formx> and <FormxField>.
// components/LoginForm.tsx
"use client";
import React from "react";
import { Formx, FormxField, regex } from "turiy-form";
import { Button } from "@/components/ui/button"; // Your project's Button component
const LoginForm = () => {
const handleLogin = (data) => {
console.log("Form Submitted:", data);
// API call to your backend would go here
alert(JSON.stringify(data, null, 2));
};
return (
<Formx
onSubmit={handleLogin}
submitButton={<Button type="submit">Log In</Button>}
className="space-y-4"
>
<FormxField
name="email"
label="Email Address"
placeholder="Enter your email"
type="email"
required
match={regex.email}
defaultValue=""
/>
<FormxField
name="password"
label="Password"
placeholder="Enter your password"
type="password"
required
match={{ type: "string", min: 6 }}
defaultValue=""
description="Password must be at least 6 characters."
/>
</Formx>
);
};
export default LoginForm;API Reference
<Formx /> Props
The main container component that wraps your form fields.
| Prop | Type | Required | Description |
| -------------- | ------------------------------------------------------------------------ | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| children | ReactElement<FormxFieldProps> \| ReactElement<FormxFieldProps>[] | Yes | One or more <FormxField> components that define the form structure. |
| onSubmit | (data: { [name: string]: string; }) => void | Yes | Callback executed with the form data when submission is successful and validation passes. |
| submitButton | ReactNode | No | A React component to render as the submit button. It will be automatically wired to the form's submission. |
| resetButton | ReactNode | No | A React component to render as the reset button. |
| onChange | (data: { [name: string]: string; selectedFieldName: string; }) => void | No | Callback triggered on any field value change. It receives the complete form data and the name of the field that was just changed. |
| onInit | (form: UseFormReturn) => void | No | Callback executed once the form is initialized, providing direct access to the react-hook-form instance for advanced control (e.g., form.setValue). |
| refine | { on: (data: object) => boolean; message: string; path: string[]; } | No | Defines a complex cross-field validation rule that runs after individual field validations. See the advanced example below. |
| className | string | No | CSS class names to apply to the div that wraps all form fields. |
<FormxField /> Props
The configuration component for each field in your form.
| Prop | Type | Required | Description |
| -------------- | ------------------------------------------------------------------- | :----------------------------: | ------------------------------------------------------------------------------------------------------------------------ |
| name | string | Yes | The unique identifier for the field. This becomes the key in the form data object. |
| label | string | Yes | The text label displayed above the form field. |
| placeholder | string | Yes | The placeholder text for the input. |
| defaultValue | string | Yes | The initial value of the field. |
| type | HTMLInputTypeAttribute \| "select" | Yes | The input type (e.g., 'text', 'password', 'email') or "select" for a dropdown menu. |
| required | boolean | No | If true, the field is mandatory. An asterisk * is automatically added to the label. |
| match | RegExp \| {type: 'string' \| 'number', min?, max?, eq?} | No | Validation rules for the field. Accepts a RegExp or a validation object. See Validation examples. |
| selectProps | { options: { label: string; value: string }[], onAdd?: () => {} } | No (Yes if type is 'select') | Configuration for a select input, including the options array and an optional onAdd function. |
| description | ReactNode | No | Helper text or description displayed below the input field. |
| cached | boolean | No | If true, the field's value is automatically saved to localStorage and reloaded on mount. Great for multi-step forms. |
| disabled | boolean | No | If true, the input field will be disabled. |
| autoFocus | boolean | No | If true, the input field will be focused automatically when the component mounts. |
| className | string | No | Custom CSS classes to apply to the field's wrapper element, allowing for custom layouts (e.g., in a grid). |
Examples
Select Fields
To create a dropdown menu, set type="select" and provide selectProps.
<FormxField
name="gender"
label="Gender"
placeholder="Select your gender"
type="select"
required
defaultValue=""
selectProps={{
options: [
{ label: "Male", value: "male" },
{ label: "Female", value: "female" },
{ label: "Other", value: "other" },
],
}}
/>Select Field with "Add" Button
You can add a + button next to a select input by providing an onAdd callback. This is useful for triggering a modal to create a new option.
const handleAddNewCategory = () => {
// Logic to open a dialog or navigate to a new page
alert("Opening modal to add a new category!");
};
<FormxField
name="category"
label="Category"
placeholder="Select a category"
type="select"
defaultValue="tech"
selectProps={{
options: [
{ label: "Technology", value: "tech" },
{ label: "Health", value: "health" },
],
onAdd: handleAddNewCategory,
}}
/>;Validation
The match prop is a powerful way to define validation rules.
1. Regex Validation
Use one of the pre-built regular expressions from the regex object or provide your own.
import { regex } from "turiy-form";
<FormxField
name="mobile"
label="Mobile No."
placeholder="+1-555-555-5555"
type="tel"
required
match={regex.mobile} // Use a predefined regex
defaultValue=""
/>;2. Length & Range Validation
Use a validation object for constraints like minimum/maximum length for strings or a numeric range.
// String length validation
<FormxField
name="username"
label="Username"
placeholder="Choose a username"
type="text"
required
match={{ type: "string", min: 4, max: 20 }}
defaultValue=""
/>
// Numeric range validation
<FormxField
name="age"
label="Age"
placeholder="Enter your age"
type="number"
required
match={{ type: "number", min: 18 }}
defaultValue=""
/>3. Cross-Field Validation (Password Confirmation)
Use the refine prop on <Formx> for validation that depends on multiple fields. This is perfect for password confirmation.
<Formx
onSubmit={handleSignup}
submitButton={<Button type="submit">Sign Up</Button>}
refine={{
// 1. The validation logic. Return true if valid.
on: (data) => data.password === data.confirmPassword,
// 2. The error message to show.
message: "Passwords do not match!",
// 3. The field where the error message should be displayed.
path: ["confirmPassword"],
}}
>
<FormxField
name="password"
label="Password"
type="password"
placeholder="Create a strong password"
required
defaultValue=""
/>
<FormxField
name="confirmPassword"
label="Confirm Password"
type="password"
placeholder="Type the password again"
required
defaultValue=""
/>
</Formx>Field Value Caching
Set the cached prop to true to automatically save a field's value in localStorage. The next time the form renders, the value will be restored. This is ideal for long forms or multi-step wizards where users might accidentally navigate away.
<FormxField
name="feedback"
label="Your Feedback"
placeholder="Share your thoughts..."
type="text" // Works with any field type
cached // This enables localStorage caching for this field
defaultValue="I think this form is..."
/>Event Handling
You can tap into the form's lifecycle with onChange and onInit.
"use client";
import React, { useState } from "react";
import { Formx, FormxField } from "turiy-form";
import { Button } from "@/components/ui/button";
const EventForm = () => {
const [liveData, setLiveData] = useState({});
const handleSubmit = (data) => {
alert("Submitted!");
};
return (
<div>
<Formx
onSubmit={handleSubmit}
submitButton={<Button type="submit">Submit</Button>}
onChange={(data) => {
console.log("Form changed!", data);
setLiveData(data);
}}
onInit={(form) => {
console.log(
"Formx initialized! You can access the react-hook-form instance:",
form
);
}}
>
<FormxField
name="first_name"
label="First Name"
placeholder="John"
defaultValue=""
/>
<FormxField
name="last_name"
label="Last Name"
placeholder="Doe"
defaultValue=""
/>
</Formx>
<div className="mt-8 p-4 border rounded bg-slate-100">
<h3 className="font-bold">Live Form Data:</h3>
<pre>{JSON.stringify(liveData, null, 2)}</pre>
</div>
</div>
);
};
export default EventForm;Utility Functions
The package also exports a few helpful utility functions.
| Function | Description |
| :------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
| regex | An object containing pre-defined regular expressions for common validations like email, mobile, password, url, etc. |
| equal | A deep equality check function. Useful for comparing the current form state with its initial state to see if any changes have been made. |
| reset | A function to programmatically reset the form to its default values. Requires access to the react-hook-form instance via onInit. |
Contributing
Contributions are welcome! If you find a bug or have a feature request, please open an issue. If you'd like to contribute code, please fork the repository and open a pull request.
Author
turiy-form © Abhijit Das, Released under the MIT License. Authored and maintained by Abhijit Das.
GitHub
License
This project is licensed under the MIT License.
