reactjstypescripttanstacktanstack-table

Making columns editable in React using Tanstack Table


I have a User Table which populates and displays data in a Tanstack Table. Some columns have the sorting feature. Now I am trying to make certain columns editable. Ex: The status column needs to be editable with a drop down of populated status, the roles column needs to be editable to text.

Code Snippet:

import { ColumnDef } from '@tanstack/react-table'
import { Button } from 'flowbite-react'
import Link from 'next/link'
import { I_UserPublic } from 'app/models/user.types'

// This type is used to define the shape of our data.
export type UserDescriptor = {
    id: string;
    firstName: string;
    lastName: string;
    userName: string;
    email: string;
    phone: string;
    title: string;
    organization: string;
    cocom: string;
    base: string;
    role: string[];
    status: string;
}

export const columns: ColumnDef<I_UserPublic>[] = [
    {
        accessorKey: "firstName",
        header: "First Name",
        enableResizing: true,
    },
    {
        accessorKey: "lastName",
        header: "Last Name",
    },
    {
        accessorKey: "userName",
        header: "Username",
    },
    {
        accessorKey: "email",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    Email
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "phone",
        header: "Phone",
    },
    {
        accessorKey: "function",
        header: "Function Area",
    },
    {
        accessorKey: "organization",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    Branch
                    <Link className="mx-4" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "cocom",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    COCOM
                    <Link className="mx-4" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "base",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    Base
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "role",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    User Role
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
    {
        accessorKey: "status",
        header: ({ column }) => {
            return (
                <span className="flex justify-between">
                    User Status
                    <Link className="" href="#" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
                        <svg className="w-4 h-4 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
                            <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 4v16M7 4l3 3M7 4 4 7m9-3h6l-6 6h6m-6.5 10 3.5-7 3.5 7M14 18h4"/>
                        </svg>
                    </Link>
                </span>
            )
        },
    },
]

The accessorKey are pulled from another file where i have hard coded data i am using for populating.

I have tried using tags from the tanstack table to make it either a dropdown or edit but cant seem to figure it out. Just want to be able to edit the populated data because this will be used as an user form to change status and role based.


Solution

  • You can specify how the cell is rendered using the cell attribute in your column config like this: cell: (info) => info.getValue(). So if you wanted to render a controlled text input in the "role" column, you could do something like:

        {
          accessorKey: "role",
          cell: (info) => {
            return <input type="text" value={info.getValue()} onChange={handleChange}/>
          },
        },
    

    where handleChange updates the data being passed into the table