Skip to main content

Table Measurement Hook


TableMeasurement is a custom hook of TableV2 to customize the Initial Column Widths by measuring the text content of each cell and return the array of new column widths.

By adding initialMinWidth, initialMaxWidth or isAutoWidth to the columns option, the hook will recalculate the minWidth, width, maxWidth and isResizable of the column, and overwriting the default behavior of these options.

Example

Following example is the usage of TableMeasurement in a large table.

Table is rendering ...
Header 0
Footer_0
Header 1
Footer_1
Header 2
Footer_2
Header Long 3
Footer_3
Header 4
Footer long 4
Header 5
Footer_5
Header 6
Footer_6
Header 7
Footer_7
Header 8
Footer_8
Header 9
Footer_9
Header 10
Footer_10
Header 11
Footer_11
Header 12
Footer_12
Header 13
Footer_13
Header 14
Footer_14
Header 15
Footer_15
Header 16
Footer_16
Header 17
Footer_17
Header 18
Footer_18
Header 19
Footer_19
Header 20
Footer_20
Header 21
Footer_21
Header 22
Footer_22
Header 23
Footer_23
Header 24
Footer_24
Header 25
Footer_25
Header 26
Footer_26
Header 27
Footer_27
Header 28
Footer_28
Header 29
Footer_29
Header 30
Footer_30
Header 31
Footer_31
Header 32
Footer_32
Header 33
Footer_33
Header 34
Footer_34
Header 35
Footer_35
Header 36
Footer_36
Header 37
Footer_37
Header 38
Footer_38
Header 39
Footer_39
Header 40
Footer_40
Header 41
Footer_41
Header 42
Footer_42
Header 43
Footer_43
Header 44
Footer_44
Header 45
Footer_45
Header 46
Footer_46
Header 47
Footer_47
Header 48
Footer_48
Header 49
Footer_49
Header 50
Footer_50
Header 51
Footer_51
Header 52
Footer_52
Header 53
Footer_53
Header 54
Footer_54
Header 55
Footer_55
Header 56
Footer_56
Header 57
Footer_57
Header 58
Footer_58
Header 59
Footer_59
Header 60
Footer_60
Header 61
Footer_61
Header 62
Footer_62
Header 63
Footer_63
Header 64
Footer_64
Header 65
Footer_65
Header 66
Footer_66
Header 67
Footer_67
Header 68
Footer_68
Header 69
Footer_69
Header 70
Footer_70
Header 71
Footer_71
Header 72
Footer_72
Header 73
Footer_73
Header 74
Footer_74
Header 75
Footer_75
Header 76
Footer_76
Header 77
Footer_77
Header 78
Footer_78
Header 79
Footer_79
Header 80
Footer_80
Header 81
Footer_81
Header 82
Footer_82
Header 83
Footer_83
Header 84
Footer_84
Header 85
Footer_85
Header 86
Footer_86
Header 87
Footer_87
Header 88
Footer_88
Header 89
Footer_89
Header 90
Footer_90
Header 91
Footer_91
Header 92
Footer_92
Header 93
Footer_93
Header 94
Footer_94
Header 95
Footer_95
Header 96
Footer_96
Header 97
Footer_97
Header 98
Footer_98
Header 99
Footer_99
Header 201
Footer_201
Header 202
Footer_202
Header 203
Footer_203
Header 204
Footer_204
Header 205
Footer_205
Header 206
Footer_206
Header 207
Footer_207
Header 208
Footer_208
Header 209
Footer_209
Header 210
Footer_210
Header 211
Footer_211
Header 212
Footer_212
Header 213
Footer_213
Header 214
Footer_214
Header 215
Footer_215
Header 216
Footer_216
Header 217
Footer_217
Header 218
Footer_218
Header 219
Footer_219
Header 220
Footer_220
Header 221
Footer_221
Header 222
Footer_222
Header 223
Footer_223
Header 224
Footer_224
Header 225
Footer_225
Header 226
Footer_226
Header 227
Footer_227
Header 228
Footer_228
Header 229
Footer_229
Header 230
Footer_230
Header 231
Footer_231
Header 232
Footer_232
Header 233
Footer_233
Header 234
Footer_234
Header 235
Footer_235
Header 236
Footer_236
Header 237
Footer_237
Header 238
Footer_238
Header 239
Footer_239
Header 240
Footer_240
Header 241
Footer_241
Header 242
Footer_242
Header 243
Footer_243
Header 244
Footer_244
Header 245
Footer_245
Header 246
Footer_246
Header 247
Footer_247
Header 248
Footer_248
Header 249
Footer_249
Header 250
Footer_250
Header 251
Footer_251
Header 252
Footer_252
Header 253
Footer_253
Header 254
Footer_254
Header 255
Footer_255
Header 256
Footer_256
Header 257
Footer_257
Header 258
Footer_258
Header 259
Footer_259
Header 260
Footer_260
Header 261
Footer_261
Header 262
Footer_262
Header 263
Footer_263
Header 264
Footer_264
Header 265
Footer_265
Header 266
Footer_266
Header 267
Footer_267
Header 268
Footer_268
Header 269
Footer_269
Header 270
Footer_270
Header 271
Footer_271
Header 272
Footer_272
Header 273
Footer_273
Header 274
Footer_274
Header 275
Footer_275
Header 276
Footer_276
Header 277
Footer_277
Header 278
Footer_278
Header 279
Footer_279
Header 280
Footer_280
Header 281
Footer_281
Header 282
Footer_282
Header 283
Footer_283
Header 284
Footer_284
Header 285
Footer_285
Header 286
Footer_286
Header 287
Footer_287
Header 288
Footer_288
Header 289
Footer_289
Header 290
Footer_290
Header 291
Footer_291
Header 292
Footer_292
Header 293
Footer_293
Header 294
Footer_294
Header 295
Footer_295
Header 296
Footer_296
Header 297
Footer_297
Header 298
Footer_298
Header 299
Footer_299
import {
TableV2,
TableColumnTypes,
Button,
Badge,
TableMeasurement,
TableMeasurementType,
CellSize
} from '@adjust/components';

const LargeTable: FC = () => {

const rowSize: CellSize = 'small';

const initialColumns: TableColumnTypes[] = Array.from(
{ length: 300 },
(_, index) => {
return {
Header: () =>
index === 3 ? `Header Long ${index}` : `Header ${index}`,
accessor: `column_${index}`,
sticky: index < 2 ? 'left' : undefined,
isResizable: true,
isAutoWidth: index < 100 ? true : index > 200 ? true : false,
Cell: ({ value }: any) =>
index === 0 ? (
<Badge label={value} size={rowSize} />
) : index === 1 ? (
<Text type="link" as={<Link to="/test">{value}</Link>}></Text>
) : (
value
),
Footer: () => (index === 4 ? `Footer long ${index}` : `Footer_${index}`)
};
}
);
const initialData = Array.from({ length: 4000 }, (_, i) => {
const obj = {} as Record<string, unknown>;
Array.from({ length: 300 }, (_, index) => {
if (index === 3 || index === 4) {
obj[`column_${index}`] = `data_${i}_${index}`;
} else {
else if (i < 1000)
obj[`column_${index}`] = `data_${i}_${index} test test`;
else obj[`column_${index}`] = `data_${i}_${index} long long test test`;
}
});
return obj;
});

const [columns, setColumns] = useState(initialColumns);
const [data, setData] = useState(initialData);

const onAddColumn = () => {
setColumns([
...columns,
...Array.from({ length: 10 }, (_, index) => {
return {
Header: `Header ${columns.length + index}`,
accessor: () => `New column ${columns.length + index}`,
id: `column_${columns.length + index}`,
isResizable: true,
isAutoWidth: true,
Footer: () => `Footer_${columns.length + index}`
};
})
]);
};

const onAddData = () => {
setData([
...data,
...Array.from({ length: 100 }, (_, i) => {
const obj = {} as Record<string, unknown>;
Array.from({ length: columns.length }, (_, index) => {
obj[`column_${index}`] = `New row data ${data.length + i}_${index} `;
});
return obj;
})
]);
};

const visualProperties = {
areColumnsBordered: true
};

return (
<TableMeasurement columns={columns} data={data} size={rowSize}>
{({ isMeasuring, measuredColumns }: TableMeasurementType) => {
// eslint-disable-next-line no-console
console.log('measuredColumns', isMeasuring, measuredColumns);
return (
<>
<Button label="Add 10 Columns" size="small" onClick={onAddColumn} />
<Button label="Add 100 Rows" size="small" onClick={onAddData} />
{isMeasuring && <div>Table is rendering ...</div>}
{!isMeasuring && (
<TableV2
data={data}
columns={measuredColumns}
height={700}
rowSize={rowSize}
visualProperties={visualProperties}
/>
)}
</>
);
}}
</TableMeasurement>
);
};

Usage

<TableMeasurement columns={columns} data={data}>
{({ isMeasuring, measuredColumns }) =>
... //children: JSX.Element | ReactNode
}
</TableMeasurement>
warning

This hook only supports for the body cells which render their value (text content) from data, not support for custom cells without data value. Please be careful if body cells are using Custom Cell Renderer

❌ Incorrect: Cell() does not have `value` from `data`.
const columns = [
{
Header: () => 'Name',
accessor: 'name',
isAutoWidth: true,
Cell: ({ row: { original, index } }) => return <Badge>{`row ${index}`}</Badge>;
Footer: () => 'Total',
}
]


✅ Correct: Cell() has `value` from `data`.
const columns = [
{
Header: () => 'Name',
accessor: 'name',
isAutoWidth: true,
Cell: ({ value }) => return <Badge>{value}</Badge>;
Footer: () => 'Total',
}
]

Return states

The hook returns TableMeasurementType as following:

StateTypeDesc
measuredColumnsTableColumnTypes[]The array of columns which is passed initially and including more: {id, width, minWidth, maxWidth, isResizable}
isMeasuringbooleantrue if the hook is measuring the column widths and hasn't returned the result

Props

NameTypeDefault
data *
Record<string, unknown>[]
columns *
TableColumnTypes[]
rowSize
"small" | "medium" | "large"
"medium"
isHeaderless
boolean
isFooterless
boolean
data-{foo}
Data attributes can be used by testing libraries to retrieve components or assert their existence
string
* - the prop is required.