react-render-form-input-cli
v1.2.1
Published
A powerful CLI tool that generates reusable React form components with automatic shadcn/ui integration. Quickly scaffold form inputs with TypeScript support, validation, and modern UI components.
Readme
React Render Form Input CLI
A powerful CLI tool that generates reusable React form components with automatic shadcn/ui integration. Quickly scaffold form inputs with TypeScript support, validation, and modern UI components.
Features
✨ Automatic shadcn/ui Integration - Detects and installs required shadcn/ui components 🎯 TypeScript Support - Fully typed form components and configurations 🔧 Multiple Input Types - Support for text, textarea, select, multi-select, currency, and searchable dropdowns 📦 Zero Configuration - Works out of the box with sensible defaults 🎨 Customizable - Easy to modify and extend generated components 🚀 Modern Stack - Built with React Hook Form, Zod validation, and Tailwind CSS
Quick Start
1. Create a Next.js Project (Recommended)
npx create-next-app@latest my-form-app --typescript --tailwind --eslint --app
cd my-form-app2. Initialize shadcn/ui
npx shadcn@latest init3. Run the CLI
npx react-render-form-input-cli@latest add-formInstallation
For global installation:
npm install -g react-render-form-input-cliOr use directly with npx (recommended):
npx react-render-form-input-cli@latest add-formPrerequisites
Your project should have:
- Next.js 13+ (recommended) or React 18+
- TypeScript
- Tailwind CSS
- shadcn/ui initialized
- A package manager (npm, yarn, or pnpm)
Note: Next.js is the recommended framework due to better shadcn/ui compatibility and active maintenance. Create React App is deprecated and may cause compatibility issues.
Usage
Basic Usage
Navigate to your Next.js project directory and run:
react-render-form add-formThis command will:
- 🔍 Check if shadcn/ui is initialized in your project
- 🚀 Initialize shadcn/ui if not present (with default settings)
- 📦 Install required shadcn/ui components (input, textarea, form, label)
- 📁 Create form components in
src/components/form/(orcomponents/form/if no src folder) - 📝 Install additional dependencies (react-hook-form, react-select)
Force Overwrite
To overwrite existing form components:
react-render-form add-form --forceGenerated Components
The CLI generates the following files:
components/
├── form/
│ ├── RenderFormInput.tsx # Main form input renderer
│ └── formInputWrapper.tsx # Form field wrapper with validation
└── types/
└── form.ts # TypeScript definitionsUsage Examples
🚀 The Power of Config-Driven Forms
The generated FormInputWrapper component revolutionizes form development by handling all form logic through configuration. No more repetitive onChange handlers, manual error display, or state management - just provide the config and everything works automatically!
Complete Form Example
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Form } from "@/components/ui/form";
import { FormInputWrapper } from "@/components/form/FormInputWrapper";
import { Button } from "@/components/ui/button";
// Define your schema
const formSchema = z.object({
contact: z.object({
email: z.string().email("Invalid email address"),
name: z.string().min(2, "Name must be at least 2 characters"),
}),
preferences: z.object({
country: z.string().min(1, "Please select a country"),
skills: z.array(z.object({ label: z.string(), value: z.string() })),
bio: z.string().optional(),
}),
salary: z.string().min(1, "Salary is required"),
});
type FormData = z.infer<typeof formSchema>;
function ContactForm() {
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: {
contact: { email: "", name: "" },
preferences: { country: "", skills: [], bio: "" },
salary: "",
},
});
const onSubmission = (data: FormData) => {
console.log("Form submitted:", data);
};
const reviewOnly = false; // Toggle for read-only mode
return (
<Form {...form}>
<form onSubmit={(event) => void form.handleSubmit(onSubmission)(event)} className="space-y-6">
{/* Email Input - Just config, no onChange needed! */}
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "input",
label: "Contact Email",
name: "contact.email",
inputType: "email",
placeHolder: "Email address",
disabled: reviewOnly,
}}
/>
{/* Name Input */}
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "input",
label: "Full Name",
name: "contact.name",
placeHolder: "Your full name",
disabled: reviewOnly,
}}
/>
{/* Country Select */}
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "select",
label: "Country",
name: "preferences.country",
placeHolder: "Select your country",
options: [
{ label: "United States", value: "us" },
{ label: "Canada", value: "ca" },
{ label: "United Kingdom", value: "uk" },
],
disabled: reviewOnly,
}}
/>
{/* Multi-Select Skills */}
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "multiSelect",
label: "Skills",
name: "preferences.skills",
placeHolder: "Select your skills",
options: [
{ label: "React", value: "react" },
{ label: "TypeScript", value: "typescript" },
{ label: "Node.js", value: "nodejs" },
{ label: "Python", value: "python" },
],
disabled: reviewOnly,
}}
/>
{/* Textarea Bio */}
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "textArea",
label: "Bio",
name: "preferences.bio",
placeHolder: "Tell us about yourself",
disabled: reviewOnly,
}}
/>
{/* Currency Input */}
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "currencyInput",
label: "Expected Salary",
name: "salary",
placeHolder: "Enter expected salary",
disabled: reviewOnly,
}}
/>
<Button type="submit" disabled={reviewOnly}>
Submit Form
</Button>
</form>
</Form>
);
}🎯 Key Benefits
✨ Zero Boilerplate: No onChange, onBlur, or manual state updates needed
🔧 Automatic Validation: Errors display automatically based on your schema
🎨 Consistent UI: All inputs follow the same design patterns
📱 Type Safety: Full TypeScript support with intellisense
🚀 Rapid Development: Add new fields in seconds, not minutes
Field Configuration Examples
Basic Input with Validation
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "input",
label: "Username",
name: "username",
inputType: "text",
placeHolder: "Enter username",
inputMaxLength: 20,
disabled: false,
}}
/>Searchable Dropdown
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "singleSearchableSelect",
label: "City",
name: "city",
placeHolder: "Search for a city",
options: [
{ label: "New York", value: "ny" },
{ label: "Los Angeles", value: "la" },
{ label: "Chicago", value: "chicago" },
{ label: "Houston", value: "houston" },
],
}}
/>Dynamic Field States
const isReadOnly = user.role === 'viewer';
const isRequired = step === 'final';
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "input",
label: "Project Name",
name: "projectName",
placeHolder: isRequired ? "Project name (required)" : "Project name",
disabled: isReadOnly,
}}
/>🔥 What Makes This Special?
Traditional Approach (lots of repetitive code):
// ❌ Old way - repetitive and error-prone
<input
value={formData.email}
onChange={(e) => setFormData({...formData, email: e.target.value})}
onBlur={() => validateEmail(formData.email)}
className="..."
/>
{errors.email && <span className="error">{errors.email}</span>}Our Approach (clean and declarative):
// ✅ New way - clean, declarative, and powerful
<FormInputWrapper
form={form}
fieldConfig={{
fieldVariant: "input",
label: "Email",
name: "email",
inputType: "email",
placeHolder: "Enter email",
}}
/>
// That's it! Validation, errors, state management - all handled automatically!Component Usage
Supported Field Types
Text Input
const textField: FormInputFields = {
name: "username",
label: "Username",
fieldVariant: "input",
inputType: "text",
placeHolder: "Enter username",
inputMaxLength: 50,
};Textarea
const textareaField: FormInputFields = {
name: "description",
label: "Description",
fieldVariant: "textArea",
placeHolder: "Enter description",
};Select Dropdown
const selectField: FormInputFields = {
name: "country",
label: "Country",
fieldVariant: "select",
options: [
{ label: "United States", value: "us" },
{ label: "Canada", value: "ca" },
{ label: "United Kingdom", value: "uk" },
],
};Multi-Select
const multiSelectField: FormInputFields = {
name: "skills",
label: "Skills",
fieldVariant: "multiSelect",
options: [
{ label: "React", value: "react" },
{ label: "TypeScript", value: "typescript" },
{ label: "Node.js", value: "nodejs" },
],
};Currency Input
const currencyField: FormInputFields = {
name: "salary",
label: "Expected Salary",
fieldVariant: "currencyInput",
placeHolder: "Enter amount",
};Searchable Select
const searchableField: FormInputFields = {
name: "city",
label: "City",
fieldVariant: "singleSearchableSelect",
options: [
{ label: "New York", value: "ny" },
{ label: "Los Angeles", value: "la" },
{ label: "Chicago", value: "chicago" },
],
};TypeScript Definitions
The generated form.ts includes comprehensive type definitions:
export interface IOptions {
label: string;
value: string;
}
export interface FormInputFields<TData extends FieldValues = FieldValues> {
name: Path<TData>;
label?: string;
fieldVariant: "input" | "textArea" | "select" | "multiSelect" | "currencyInput" | "singleSearchableSelect";
inputType?: "text" | "email" | "password" | "number";
placeHolder?: string;
options?: IOptions[];
disabled?: boolean;
inputMaxLength?: number;
prefixIcon?: React.ReactNode;
}Customization
The generated components use Tailwind CSS classes and can be easily customized:
- Styling: Modify the
classNameprops in the generated components - Validation: Add Zod schemas or custom validation logic
- New Field Types: Extend the
fieldVarianttype and add cases toRenderFormInput.tsx
Dependencies
The CLI automatically installs these dependencies:
- shadcn/ui components:
input,textarea,form,label - react-hook-form: Form state management and validation
- react-select: Enhanced select components
Troubleshooting
shadcn/ui Not Initializing
If automatic shadcn/ui initialization fails:
npx shadcn@latest initMissing Components
If shadcn/ui components fail to install:
npx shadcn@latest add input textarea form labelImport Path Issues
Ensure your tsconfig.json has path mapping configured:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Changelog
v1.1.2
- ✨ Added automatic shadcn/ui integration
- 🔧 Improved dependency management
- 📦 Enhanced TypeScript support
- 🎨 Updated component templates
- 🚀 Recommended Next.js setup for better compatibility
- ⚠️ Added deprecation notice for Create React App
Made with ❤️ for the React community
