Skip to main content

Form Components

** Last Built**: September 2, 2025 at 4:19 PM Build beautiful forms with React SuperAdmin's form components.

Basic Form

Live Editor
import React, { useState } from 'react';
function BasicForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    role: ''
  });
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form submitted:', formData);
  };
  return (
    <form onSubmit={handleSubmit} className="space-y-4 max-w-md">
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Name *
  </label>
  <input
  type="text"
  value={formData.name}
  onChange={(e) => setFormData({...formData, name: e.target.value})}
  placeholder="Enter your name"
  className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
  required
  />
  </div>
 <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Email *
  </label>
  <input
  type="email"
  value={formData.email}
  onChange={(e) => setFormData({...formData, email: e.target.value})}
  placeholder="Enter your email"
  className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
  required
  />
  </div>
 <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Role
  </label>
  <select
  value={formData.role}
  onChange={(e) => setFormData({...formData, role: e.target.value})}
  className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
  >
  <option value="">Select a role</option>
  <option value="admin">Administrator</option>
  <option value="user">User</option>
  <option value="moderator">Moderator</option>
  </select>
  </div>
 <button  type="submit"  className="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
  >
  Submit Form
  </button>
    </form>
  );
}
Result
Loading...

Data Table Example

Live Editor
import React, { useState } from 'react';
function DataTableExample() {
  const [data] = useState([
    { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active', role: 'admin' },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive', role: 'user' },
    { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active', role: 'moderator' },
  ]);
  const getStatusBadge = (status) => {
    const baseClasses = "px-2 py-1 text-xs font-medium rounded-full";
    if (status === 'active') {
  return `${baseClasses} bg-green-100 text-green-800`;
    }
    return `${baseClasses} bg-yellow-100 text-yellow-800`;
  };
  return (
    <div className="overflow-x-auto">
  <table className="min-w-full divide-y divide-gray-200">
  <thead className="bg-gray-50">
  <tr>
  <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
  Name
  </th>
  <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
  Email
  </th>
  <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
  Status
  </th>
  <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
  Role
  </th>
  <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
  Actions
  </th>
  </tr>
  </thead>
  <tbody className="bg-white divide-y divide-gray-200">
  {data.map((user) => (
  <tr key={user.id}>
  <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
  {user.name}
  </td>
  <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  {user.email}
  </td>
  <td className="px-6 py-4 whitespace-nowrap">
  <span className={getStatusBadge(user.status)}>
  {user.status}
  </span>
  </td>
  <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  {user.role}
  </td>
  <td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
  <div className="space-x-2">
  <button className="text-blue-600 hover:text-blue-900">
  Edit
  </button>
  <button className="text-red-600 hover:text-red-900">
  Delete
  </button>
  </div>
  </td>
  </tr>
  ))}
  </tbody>
  </table>
    </div>
  );
}
Result
Loading...

Live CRUD Operations

Live Editor
import React, { useState } from 'react';
function LiveCRUDExample() {
  const [users, setUsers] = useState([
    { id: 1, name: 'Alice', email: 'alice@example.com' },
    { id: 2, name: 'Bob', email: 'bob@example.com' },
  ]);
  const [showForm, setShowForm] = useState(false);
  const [editingUser, setEditingUser] = useState(null);
  const [formData, setFormData] = useState({ name: '', email: '' });
  const addUser = (e) => {
    e.preventDefault();
    const newUser = { ...formData, id: Date.now() };
    setUsers([...users, newUser]);
    setShowForm(false);
    setFormData({ name: '', email: '' });
  };
  const updateUser = (id, userData) => {
    setUsers(users.map(user => user.id === id ? { ...user, ...userData } : user));
    setEditingUser(null);
    setFormData({ name: '', email: '' });
  };
  const deleteUser = (id) => {
    setUsers(users.filter(user => user.id !== id));
  };
  const startEdit = (user) => {
    setEditingUser(user);
    setFormData({ name: user.name, email: user.email });
    setShowForm(true);
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    if (editingUser) {
  updateUser(editingUser.id, formData);
    } else {
  addUser(e);
  };
  return (
    <div className="space-y-4">
  <button  onClick={() => {
  setShowForm(true);
  setEditingUser(null);
  setFormData({ name: '', email: '' });
  }}
  className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
  >
  Add New User
  </button>
 <div className="space-y-2">
  {users.map(user => (
  <div key={user.id} className="flex justify-between items-center p-3 border rounded">
  <div>
  <div className="font-medium">{user.name}</div>
  <div className="text-sm text-gray-600">{user.email}</div>
  </div>
  <div className="space-x-2">
  <button  onClick={() => startEdit(user)}
  className="px-3 py-1 text-sm border border-gray-300 rounded hover:bg-gray-50"
  >
  Edit
  </button>
  <button  onClick={() => deleteUser(user.id)}
  className="px-3 py-1 text-sm text-red-600 hover:text-red-900"
  >
  Delete
  </button>
  </div>
  ))}
  </div>
  {showForm && (
  <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
  <div className="bg-white rounded-lg p-6 max-w-md w-full">
  <h3 className="text-lg font-medium mb-4">
  {editingUser ? 'Edit User' : 'Add New User'}
  </h3>
  <form onSubmit={handleSubmit} className="space-y-4">
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Name
  </label>
  <input
  type="text"
  value={formData.name}
  onChange={(e) => setFormData({...formData, name: e.target.value})}
  className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
  required
  />
  </div>
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Email
  </label>
  <input
  type="email"
  value={formData.email}
  onChange={(e) => setFormData({...formData, email: e.target.value})}
  className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
  required
  />
  </div>
  <div className="flex space-x-2">
  <button  type="submit"
  className="flex-1 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
  >
  {editingUser ? 'Update' : 'Add'}
  </button>
  <button  type="button"
  onClick={() => {
  setShowForm(false);
  setEditingUser(null);
  setFormData({ name: '', email: '' });
  }}
  className="flex-1 px-4 py-2 border border-gray-300 text-gray-700 rounded hover:bg-gray-50"
  >
  Cancel
  </button>
  </div>
  </form>
  </div>
  )}
    </div>
  );
}
Result
Loading...

Form Validation

Live Editor
import React, { useState } from 'react';
function FormValidation() {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    password: '',
    confirmPassword: ''
  });
  const [errors, setErrors] = useState({});
  const [touched, setTouched] = useState({});
  const validateField = (name, value) => {
    switch (name) {
  case 'username':
  if (value.length < 3) return 'Username must be at least 3 characters';
  if (value.length > 20) return 'Username must be less than 20 characters';
  return '';
  case 'email':
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(value)) return 'Please enter a valid email';
  return '';
  case 'password':
  if (value.length < 6) return 'Password must be at least 6 characters';
  return '';
  case 'confirmPassword':
  if (value !== formData.password) return 'Passwords do not match';
  return '';
  default:
  return '';
  };
  const handleChange = (name, value) => {
    setFormData({ ...formData, [name]: value });
    if (touched[name]) {
  const error = validateField(name, value);
  setErrors({ ...errors, [name]: error });
  };
  const handleBlur = (name) => {
    setTouched({ ...touched, [name]: true });
    const error = validateField(name, formData[name]);
    setErrors({ ...errors, [name]: error });
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    const newErrors = {};
    Object.keys(formData).forEach(key => {
  const error = validateField(key, formData[key]);
  if (error) newErrors[key] = error;
    });
 if (Object.keys(newErrors).length === 0) {
  console.log('Form submitted successfully:', formData);
    } else {
  setErrors(newErrors);
  setTouched(Object.keys(formData).reduce((acc, key) => ({ ...acc, [key]: true }), {}));
  };
  return (
    <form onSubmit={handleSubmit} className="space-y-4 max-w-md">
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Username
  </label>
  <input
  type="text"
  value={formData.username}
  onChange={(e) => handleChange('username', e.target.value)}
  onBlur={() => handleBlur('username')}
  className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
  touched.username && errors.username ? 'border-red-500' : 'border-gray-300'
  }`}
  />
  {touched.username && errors.username && (
  <p className="mt-1 text-sm text-red-600">{errors.username}</p>
  )}
  </div>
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Email
  </label>
  <input
  type="email"
  value={formData.email}
  onChange={(e) => handleChange('email', e.target.value)}
  onBlur={() => handleBlur('email')}
  className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
  touched.email && errors.email ? 'border-red-500' : 'border-gray-300'
  }`}
  />
  {touched.email && errors.email && (
  <p className="mt-1 text-sm text-red-600">{errors.email}</p>
  )}
  </div>
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Password
  </label>
  <input
  type="password"
  value={formData.password}
  onChange={(e) => handleChange('password', e.target.value)}
  onBlur={() => handleBlur('password')}
  className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
  touched.password && errors.password ? 'border-red-500' : 'border-gray-300'
  }`}
  />
  {touched.password && errors.password && (
  <p className="mt-1 text-sm text-red-600">{errors.password}</p>
  )}
  </div>
  <div>
  <label className="block text-sm font-medium text-gray-700 mb-1">
  Confirm Password
  </label>
  <input
  type="password"
  value={formData.confirmPassword}
  onChange={(e) => handleChange('confirmPassword', e.target.value)}
  onBlur={() => handleBlur('confirmPassword')}
  className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
  touched.confirmPassword && errors.confirmPassword ? 'border-red-500' : 'border-gray-300'
  }`}
  />
  {touched.confirmPassword && errors.confirmPassword && (
  <p className="mt-1 text-sm text-red-600">{errors.confirmPassword}</p>
  )}
  </div>
  <button  type="submit"  className="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
  >
  Submit
  </button>
    </form>
  );
}
Result
Loading...

Key Features

  • Real-time Validation: Instant feedback on form errors
  • Accessible: Proper labels and error messages
  • Responsive: Works on all device sizes
  • Customizable: Easy to style and extend
  • Type Safe: Full TypeScript support

Best Practices

  1. Always validate on blur: Don't show errors until user has interacted with a field
  2. Clear error messages: Tell users exactly what's wrong and how to fix it
  3. Accessible labels: Use proper <label> elements for screen readers
  4. Loading states: Show feedback during form submission
  5. Success feedback: Confirm when forms are submitted successfully