0

First time here.

I need to change the behaviour of the title column in antd Table to be resizable. Code in TS + React + antd + react-resizable.

The table column are resizable, there may be fixed/pinned column.

When you resize the last column in the table, it will increase the width BUT the RH will stay sticked to the table side. So effectively the RH will stay there and width increase will be applied along with scrolling such that the RH will always be visible, sticked to the right side of the table.

I want same effect for the rest of the columns. ie.

  • if there is fixed column on the left side, when you resize the last column on the right side, it should increase the width of the column and the RH should stay sticked to the side of the fixed column edge.

  • if there is no fixed column on the left side, when you resize the last column on the right side, it should increase the width of the column and the RH should stay sticked to the right side of the table.

This is the code for resizable title column.

import React, { useState } from 'react';
import { Resizable, ResizeCallbackData } from 'react-resizable';
import 'react-resizable/css/styles.css';
const ResizableTitle = (
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 props: React.HTMLAttributes<any> & {
 onResize: (
 e: React.SyntheticEvent<Element>,
 data: ResizeCallbackData
 ) => void;
 onResizeStop: (
 e: React.SyntheticEvent<Element>,
 data: ResizeCallbackData
 ) => void;
 width: number;
 minWidth: number;
 isResize: boolean;
 }
) => {
 const { onResize, width, onResizeStop, minWidth, isResize, ...restProps } =
 props;
 const [isFieldResizing, setIsFieldResizing] = useState(false);
 if (!width || !isResize) {
 return <th {...restProps} />;
 } else {
 return (
 <Resizable
 width={width}
 height={0}
 handle={
 <span
 className="react-resizable-handle"
 onClick={(e) => {
 e.stopPropagation();
 }}
 />
 }
 onResize={onResize}
 draggableOpts={{ enableUserSelectHack: false }}
 onResizeStart={(e) => {
 e.stopPropagation();
 setIsFieldResizing(true);
 document.body.classList.add('no-select');
 }}
 onResizeStop={(e, data) => {
 setIsFieldResizing(false);
 onResizeStop(e, data);
 document.body.classList.remove('no-select');
 }}
 minConstraints={[minWidth, 0]}>
 <th
 {...restProps}
 className={
 isFieldResizing
 ? restProps.className?.concat(' is-resizing')
 : restProps.className
 }
 />
 </Resizable>
 );
 }
};
export default ResizableTitle;

This is a sample on how its used with antd Table.

import { Table } from 'antd';
import ResizableTitle from './components/resizable-title';
// ...
const ListForms = ({ formsRef }: IListForms) => {
 // ....
 return (
 <div className="table-section table-section-with-search">
 <>
 <Table
 className="tableCellPadding-9"
 //@ts-ignore
 columns={resizableColumns}
 onChange={onChangeTable}
 showSorterTooltip={false}
 loading={listFormsIsLoading}
 components={{
 header: {
 cell: ResizableTitle,
 },
 }}
 dataSource={formsList}
 pagination={pagination}
 locale={{
 emptyText: (
 <NoDataFound
 icon={<NoPreviewIcon />}
 title={t('common.labels.no_result_found')}
 // description={t(
 // 'common.labels.no_forms_added_description'
 // )}
 />
 ),
 }}
 rowSelection={{
 type: 'checkbox',
 selectedRowKeys: deleteFormsIds.map((item) => item),
 onChange: onFormsSelectChange,
 onSelectAll: isAllFormsSelected
 ? onClearAllForms
 : onSelectAllForms,
 fixed: 'left',
 columnWidth: '50px',
 }}
 rowKey="id"
 scroll={
 formsList && formsList.length > 0
 ? { x: '1050', y: '400' }
 : {}
 }
 tableLayout={
 formsList && formsList.length > 0 ? 'fixed' : 'auto'
 }
 />
 </>
 </div>
 // ...
 );
};
export default ListForms;

Here is css(scss) in case neede:

.ant-table-thead {
 > tr > th {
 .react-resizable-handle {
 opacity: 0;
 background: none;
 transition: $transition-default;
 right: 0;
 top: 0;
 z-index: 9;
 height: 100%;
 width: 12px;
 padding: 0;
 &:after {
 content: "";
 position: absolute;
 top: 5px;
 bottom: 5px;
 left: 3px;
 z-index: 1;
 width: 1px;
 background-color: $border-color-split;
 }
 &:hover {
 opacity: 1;
 }
 }
 &.is-resizing {
 .react-resizable-handle {
 opacity: 1;
 transition: $transition-default;
 cursor: col-resize;
 }
 }
 &:hover {
 .react-resizable-handle {
 opacity: 1;
 transition: $transition-default;
 cursor: col-resize;
 }
 .table-sort-icon {
 width: 16px;
 opacity: 1;
 transition: $transition-default;
 }
 }
 }
}
asked Jun 11, 2025 at 6:49

1 Answer 1

0

To make the resize handle stick to the edge of the previous column or fixed column, use position: absolute; right: 0; for .react-resizable-handle and ensure the <th> has position: relative . Also, apply min-width: 0 to the table and column headers to allow shrinking.

To for scroll behaviour and RH stickiness, see below;

.ant-table table {
 table-layout: fixed;
 min-width: 100%;
}
.ant-table-thead > tr > th {
 position: relative;
 overflow: visible;
 .react-resizable-handle {
 position: absolute;
 top: 0;
 right: 0;
 height: 100%;
 cursor: col-resize;
 z-index: 1;
 }
}

Also, in JS, when resizing, only update the target column's width. Avoid forcing table reflows that affect layout.

answered Jun 11, 2025 at 20:58
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.