GridView Component - CRUD Operations ✨

Complete data grid with Create, Read, Update, Delete operations. Powered by JSONPlaceholder API for demo purposes.

Key Features

  • Full CRUD: Create, Read, Update, Delete operations
  • Inline Editing: Edit rows directly in modal forms
  • Auto Refresh: Built-in refresh button
  • Validation: Form validation with Yup
  • Type Safe: Full TypeScript support
  • Nested Objects: Support for complex data structures
  • Responsive: Mobile-friendly design
  • Loading States: Skeleton loaders and spinners

Demo API: JSONPlaceholder

This demo uses JSONPlaceholder, a free fake REST API for testing and prototyping.

📋 Note: JSONPlaceholder is a mock API, so:

  • Create: Will simulate creation but won't persist
  • Update: Will simulate update but won't save
  • Delete: Will simulate deletion but won't remove
  • Changes are visible locally until you refresh the page

Live Demo

Try adding, editing, and deleting users. Click the Add User button to create a new user, click the edit icon to modify, or delete icon to remove.

Users

All Users

🚀 Direct External API Demo (No Proxy!)

This GridView fetches data directly from https://jsonplaceholder.typicode.com/users without any proxy endpoint. Notice we don't use responseProp because the API returns an array directly.

Users (Direct API)

All Users (Direct API)

Code for this example:

<GridView<User>
  name="User"
  names="Users"
  apiUrl="https://jsonplaceholder.typicode.com/users"
  fields={userFields}
  idFieldName="id"
  showHeader={true}
  showRefresh={true}
  // NO responseProp! API returns array directly: [...]
/>

// Read-only mode - no add/edit/delete buttons shown
// For CRUD operations, you need proxy endpoints

How to Build This

Step 1: Define Your Data Type

Step 2: Define Fields Configuration

Step 3: Render GridView Component

Complete Working Example

API Response Format

GridView expects specific response formats from your API endpoints:

GET /api/users (List)

{
  "success": true,
  "data": [
    { "id": 1, "name": "John", "email": "john@example.com" },
    { "id": 2, "name": "Jane", "email": "jane@example.com" }
  ]
}

// Use responseProp="data" to extract the array

GET /api/users/:id (Single Item - for Edit)

{
  "success": true,
  "data": { "id": 1, "name": "John", "email": "john@example.com" }
}

// Use editResponseProp="data" to extract the object

POST /api/users (Create)

// Response
{
  "success": true,
  "data": { "id": 3, "name": "New User", "email": "new@example.com" },
  "message": "User created successfully"
}

PUT /api/users/:id (Update)

// Response
{
  "success": true,
  "data": { "id": 1, "name": "Updated Name", "email": "updated@example.com" },
  "message": "User updated successfully"
}

DELETE /api/users/:id (Delete)

// Response
{
  "success": true,
  "message": "User deleted successfully"
}

GridView Props

PropTypeRequiredDescription
namestringYesSingular name (e.g., "User")
namesstringNoPlural name (e.g., "Users")
apiUrlstringYesAPI endpoint to fetch data
fieldsField<T>YesField definitions for grid columns
idFieldNamekeyof TNoID field name (default: "id")
addApiUrlstringNoAPI endpoint for creating items
editApiUrlstringNoAPI endpoint for updating items (use $<row.id> or [id] placeholder)
deleteApiUrlstringNoAPI endpoint for deleting items (use $<row.id> or [id] placeholder)
showHeaderbooleanNoShow grid header (default: true)
showRefreshbooleanNoShow refresh button (default: false)
responsePropstringNoProperty to extract array from API response (e.g., "data")
editResponsePropstringNoProperty to extract object from edit API response (e.g., "data")
refetchOnEditbooleanNoRefetch data before editing (default: false)
autoRefreshbooleanNoAuto-refresh data periodically

Using External APIs Directly (No Proxy Needed!)

You can use external APIs like JSONPlaceholder directly without creating proxy endpoints. Just omit responseProp if the API returns an array directly, or use it to extract the data from a wrapper object.

Example 1: API Returns Array Directly

When the API returns [{...}, {...}] directly (like JSONPlaceholder):

// JSONPlaceholder returns: [{ id: 1, name: "..." }, ...]
// DON'T use responseProp!

<GridView<User>
  name="User"
  names="Users"
  apiUrl="https://jsonplaceholder.typicode.com/users"
  fields={userFields}
  idFieldName="id"
  showHeader={true}
  showRefresh={true}
  // Note: No responseProp! API returns array directly
/>

// Read-only mode (no CRUD operations)
// If you want to enable CRUD, you'll need proxy endpoints

Example 2: API Returns Wrapped Response

When the API returns {success: true, data: [{...}, ...]}:

// API returns: { success: true, data: [...] }
// USE responseProp="data"

<GridView<User>
  name="User"
  names="Users"
  apiUrl="/api/users"
  fields={userFields}
  idFieldName="id"
  responseProp="data"  // Extract array from response.data
  showHeader={true}
  showRefresh={true}
/>

Example 3: Nested Data with objectProp

When each item has a nested object you want to extract:

// API returns: { data: [{ id: 1, user: { name: "...", email: "..." } }] }
// Extract 'user' from each item

<GridView<User>
  name="User"
  names="Users"
  apiUrl="/api/users"
  fields={userFields}
  idFieldName="id"
  responseProp="data"    // Extract array from response.data
  objectProp="user"      // Extract 'user' object from each item
  showHeader={true}
/>

Quick Reference: When to Use What

API Response FormatProps to Use
[{...}, {...}]No responseProp needed
{data: [{...}]}responseProp="data"
{result: [{...}]}responseProp="result"
[{id: 1, user: {...}}]objectProp="user"

⚠️ Important Notes:

  • CORS: External APIs must allow CORS from your domain
  • Read-Only: Direct external API usage is typically read-only
  • CRUD Operations: For Create/Update/Delete, you need proxy endpoints
  • Authentication: API keys/tokens should be in proxy endpoints, not client-side
  • Rate Limits: Be aware of API rate limiting

Advanced Features

Custom Row Actions

Add custom buttons/actions to each row:

<GridView
  customActions={(item, fetchData) => (
    <button onClick={() => handleCustomAction(item)}>
      Custom Action
    </button>
  )}
/>

Nested Objects

Handle complex nested data structures:

company: {
  name: 'company',
  label: 'Company',
  type: 'object',
  fields: {
    name: {
      name: 'name',
      label: 'Company Name',
      type: 'text',
    },
    address: {
      name: 'address',
      label: 'Address',
      type: 'text',
    },
  },
}

Row Click Handling

Handle clicks on rows:

<GridView
  onRowClick={(e, item, setDetailedView) => {
    console.log('Clicked row:', item);
    // Navigate or show details
  }}
/>