Want to skip to the implementation? Check out these examples:
By default, columns are ordered in the order they are defined in the columns array. However, you can manually specify the column order using the columnOrder state. Other features like column pinning and grouping can also affect the column order.
There are 3 table features that can reorder columns, which happen in the following order:
Note: columnOrder state will only affect unpinned columns if used in conjunction with column pinning.
If you don't provide a columnOrder state, TanStack Table will just use the order of the columns in the columns array. However, you can provide an array of string column ids to the columnOrder state to specify the order of the columns.
If all you need to do is specify the initial column order, you can just specify the columnOrder state in the initialState table option.
const table = useReactTable({
//...
initialState: {
columnOrder: ['columnId1', 'columnId2', 'columnId3'],
}
//...
});
const table = useReactTable({
//...
initialState: {
columnOrder: ['columnId1', 'columnId2', 'columnId3'],
}
//...
});
Note: If you are using the state table option to also specify the columnOrder state, the initialState will have no effect. Only specify particular states in either initialState or state, not both.
If you need to dynamically change the column order, or set the column order after the table has been initialized, you can manage the columnOrder state just like any other table state.
const [columnOrder, setColumnOrder] = useState<string[]>(['columnId1', 'columnId2', 'columnId3']); //optionally initialize the column order
//...
const table = useReactTable({
//...
state: {
columnOrder,
//...
}
onColumnOrderChange: setColumnOrder,
//...
});
const [columnOrder, setColumnOrder] = useState<string[]>(['columnId1', 'columnId2', 'columnId3']); //optionally initialize the column order
//...
const table = useReactTable({
//...
state: {
columnOrder,
//...
}
onColumnOrderChange: setColumnOrder,
//...
});
If the table has UI that allows the user to reorder columns, you can set up the logic something like this:
const [columnOrder, setColumnOrder] = useState<string[]>(columns.map(c => c.id));
//depending on your dnd solution of choice, you may or may not need state like this
const [movingColumnId, setMovingColumnId] = useState<string | null>(null);
const [targetColumnId, setTargetColumnId] = useState<string | null>(null);
//util function to splice and reorder the columnOrder array
const reorderColumn = <TData extends RowData>(
movingColumnId: Column<TData>,
targetColumnId: Column<TData>,
): string[] => {
const newColumnOrder = [...columnOrder];
newColumnOrder.splice(
newColumnOrder.indexOf(targetColumnId),
0,
newColumnOrder.splice(newColumnOrder.indexOf(movingColumnId), 1)[0],
);
setColumnOrder(newColumnOrder);
};
const handleDragEnd = (e: DragEvent) => {
if(!movingColumnId || !targetColumnId) return;
setColumnOrder(reorderColumn(movingColumnId, targetColumnId));
};
//use your dnd solution of choice
const [columnOrder, setColumnOrder] = useState<string[]>(columns.map(c => c.id));
//depending on your dnd solution of choice, you may or may not need state like this
const [movingColumnId, setMovingColumnId] = useState<string | null>(null);
const [targetColumnId, setTargetColumnId] = useState<string | null>(null);
//util function to splice and reorder the columnOrder array
const reorderColumn = <TData extends RowData>(
movingColumnId: Column<TData>,
targetColumnId: Column<TData>,
): string[] => {
const newColumnOrder = [...columnOrder];
newColumnOrder.splice(
newColumnOrder.indexOf(targetColumnId),
0,
newColumnOrder.splice(newColumnOrder.indexOf(movingColumnId), 1)[0],
);
setColumnOrder(newColumnOrder);
};
const handleDragEnd = (e: DragEvent) => {
if(!movingColumnId || !targetColumnId) return;
setColumnOrder(reorderColumn(movingColumnId, targetColumnId));
};
//use your dnd solution of choice
There are undoubtedly many ways to implement drag and drop features along-side TanStack Table. Here are a few suggestions in order for you to not have a bad time:
Do NOT try to use "react-dnd" if you are using React 18 or newer. React DnD was an important library for its time, but it now does not get updated very often, and it has incompatibilities with React 18, especially in React Strict Mode. It is still possible to get it to work, but there are newer alternatives that have better compatibility and are more actively maintained. React DnD's Provider may also interfere and conflict with any other DnD solutions you may want to try in your app.
Use "@dnd-kit/core". DnD Kit is a modern, modular and lightweight drag and drop library that is highly compatible with the modern React ecosystem, and it works well with semantic <table> markup. Both of the official TanStack DnD examples, Column DnD and Row DnD, now use DnD Kit.
Consider other DnD libraries like "react-beautiful-dnd", but be aware of their potentially large bundle sizes, maintenance status, and compatibility with <table> markup.
Consider using native browser events and state management to implement lightweight drag and drop features. However, be aware that this approach may not be best for mobile users if you do not go the extra mile to implement proper touch events. Material React Table V2 is an example of a library that implements TanStack Table with only browser drag and drop events such as onDragStart, onDragEnd, onDragEnter and no other dependencies. Browse its source code to see how it is done.
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.