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;
}
}
}
}
1 Answer 1
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.
Comments
Explore related questions
See similar questions with these tags.