Published on

Optimal Delete Confirmation Dialog in Shadcn Data Table

Authors
  • Name
    Ripal & Zalak
    Twitter

Optimal Delete Confirmation Dialog in Shadcn Data Table

When implementing a delete confirmation dialog in a Shadcn Data Table, it's crucial to balance performance and usability. This guide outlines an optimal approach that avoids rendering unnecessary components while maintaining a clean and efficient user interface.

Overview

The challenge arises when deciding how to handle the dialog for each row. Rendering a Dialog component for every row can be inefficient, especially in large datasets. Instead, we recommend using a single dialog component managed by state.

Step-by-Step Implementation

Step 1: Centralize the Dialog Component

Create a single reusable dialog component and control its visibility through state.

import { useState } from 'react'
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter } from 'shadcn/ui/dialog'
import { Button } from 'shadcn/ui/button'

export function DeleteConfirmationDialog({ isOpen, onClose, onConfirm }) {
  return (
    <Dialog open={isOpen} onOpenChange={onClose}>
      <DialogContent>
        <DialogHeader>
          <h3>Confirm Delete</h3>
        </DialogHeader>
        <p>Are you sure you want to delete this item?</p>
        <DialogFooter>
          <Button variant="secondary" onClick={onClose}>
            Cancel
          </Button>
          <Button variant="destructive" onClick={onConfirm}>
            Delete
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

Step 2: Manage State in the Parent Component

Use state in the parent component to track the selected row and control the dialog visibility.

import { useState } from 'react'
import { DataTable } from './data-table'
import { DeleteConfirmationDialog } from './delete-dialog'

export default function UserTable({ data }) {
  const [dialogOpen, setDialogOpen] = useState(false)
  const [selectedRow, setSelectedRow] = useState(null)

  const handleDelete = (row) => {
    setSelectedRow(row)
    setDialogOpen(true)
  }

  const confirmDelete = () => {
    console.log('Deleting row:', selectedRow)
    setDialogOpen(false)
    setSelectedRow(null)
  }

  return (
    <div>
      <DataTable
        data={data}
        columns={[
          {
            accessorKey: 'name',
            header: 'Name',
            cell: ({ row }) => row.original.name,
          },
          {
            accessorKey: 'delete',
            header: '',
            cell: ({ row }) => (
              <Button variant="destructive" onClick={() => handleDelete(row.original)}>
                Delete
              </Button>
            ),
          },
        ]}
      />

      <DeleteConfirmationDialog
        isOpen={dialogOpen}
        onClose={() => setDialogOpen(false)}
        onConfirm={confirmDelete}
      />
    </div>
  )
}

Step 3: Optimize the Table Columns

Pass only essential functionality to the cell property of each column to keep the implementation lean.

export const columns = [
  {
    accessorKey: 'name',
    header: 'Name',
    cell: ({ row }) => row.original.name,
  },
  {
    accessorKey: 'delete',
    header: '',
    cell: ({ row }) => (
      <Button variant="destructive" onClick={() => handleDelete(row.original)}>
        Delete
      </Button>
    ),
  },
]

Benefits of This Approach

  1. Performance Optimization: Avoids rendering multiple dialog components for every row.
  2. Centralized Control: The dialog state and logic are handled in one place, making the code easier to manage.
  3. Scalability: Suitable for large datasets where rendering dialogs for each row could degrade performance.

FAQs

1. Why shouldn’t I render a dialog for every row?

Rendering a dialog for each row increases memory usage and can slow down rendering, especially for large datasets.

2. How can I handle asynchronous delete actions?

Update the confirmDelete function to call an API or dispatch an action for deletion, then close the dialog upon success.

3. Can I customize the dialog appearance?

Yes, use the className prop in Shadcn components or add custom styles to match your design system.

Conclusion

Using a single dialog component managed by state is an optimal way to handle delete confirmation in a Shadcn Data Table. This approach ensures better performance, maintainability, and scalability while providing a seamless user experience.