0
# Formatters and Display
1
2
Cell formatting functionality providing built-in formatters and infrastructure for custom cell display components.
3
4
## Capabilities
5
6
### Built-in Formatters
7
8
Pre-built formatter components for common cell display scenarios.
9
10
```javascript { .api }
11
const formatters = {
12
/** Basic cell formatter for simple value display */
13
SimpleCellFormatter: React.ComponentType<FormatterProps>;
14
/** Checkbox formatter for select-all functionality in headers */
15
SelectAll: React.ComponentType<FormatterProps>;
16
};
17
18
interface FormatterProps {
19
/** Cell value to format and display */
20
value: any;
21
/** Complete row data object */
22
row: any;
23
/** Column definition */
24
column: Column;
25
/** Row index */
26
rowIdx: number;
27
/** Whether the cell is currently selected */
28
isSelected?: boolean;
29
/** Whether row selection is enabled */
30
isRowSelected?: boolean;
31
/** Additional properties passed from column definition */
32
[key: string]: any;
33
}
34
```
35
36
### SimpleCellFormatter
37
38
Basic formatter that displays cell values as text with null/undefined handling.
39
40
```javascript { .api }
41
/**
42
* Simple cell formatter for displaying basic text values
43
* Handles null/undefined values gracefully
44
* Supports title attribute for hover tooltips
45
*/
46
const SimpleCellFormatter: React.ComponentType<FormatterProps>;
47
```
48
49
**Usage Example:**
50
51
```javascript
52
import ReactDataGrid, { formatters } from 'react-data-grid';
53
54
const columns = [
55
{ key: 'id', name: 'ID' },
56
{
57
key: 'name',
58
name: 'Name',
59
formatter: <formatters.SimpleCellFormatter />
60
},
61
{
62
key: 'description',
63
name: 'Description',
64
formatter: <formatters.SimpleCellFormatter />
65
}
66
];
67
68
<ReactDataGrid
69
columns={columns}
70
rowGetter={i => rows[i]}
71
rowsCount={rows.length}
72
minHeight={400}
73
/>
74
```
75
76
### SelectAll Formatter
77
78
Specialized formatter for rendering select-all checkboxes in header cells.
79
80
```javascript { .api }
81
/**
82
* Select-all checkbox formatter for header cells
83
* Provides master checkbox to select/deselect all rows
84
* Works with rowSelection configuration
85
*/
86
const SelectAll: React.ComponentType<FormatterProps>;
87
```
88
89
**Usage Example:**
90
91
```javascript
92
import ReactDataGrid, { formatters } from 'react-data-grid';
93
94
const columns = [
95
{
96
key: 'select',
97
name: '',
98
formatter: <formatters.SelectAll />,
99
width: 60,
100
resizable: false,
101
sortable: false,
102
frozen: true
103
},
104
{ key: 'id', name: 'ID' },
105
{ key: 'name', name: 'Name' }
106
];
107
108
const rowSelection = {
109
showCheckbox: true,
110
enableShiftSelect: true,
111
onRowsSelected: (rows) => console.log('Selected:', rows),
112
onRowsDeselected: (rows) => console.log('Deselected:', rows),
113
selectBy: {
114
indexes: selectedIndexes
115
}
116
};
117
118
<ReactDataGrid
119
columns={columns}
120
rowGetter={i => rows[i]}
121
rowsCount={rows.length}
122
minHeight={400}
123
rowSelection={rowSelection}
124
/>
125
```
126
127
### Custom Formatter Creation
128
129
Creating custom formatters for specialized cell display requirements.
130
131
```javascript { .api }
132
/**
133
* Interface for custom formatter components
134
* Receives cell data and returns JSX for display
135
*/
136
interface CustomFormatter extends React.Component<FormatterProps> {
137
render(): JSX.Element;
138
}
139
```
140
141
**Custom Formatter Examples:**
142
143
```javascript
144
import React from 'react';
145
146
// Currency formatter
147
const CurrencyFormatter = ({ value }) => {
148
const formattedValue = new Intl.NumberFormat('en-US', {
149
style: 'currency',
150
currency: 'USD'
151
}).format(value || 0);
152
153
return (
154
<div style={{ textAlign: 'right', fontWeight: 'bold' }}>
155
{formattedValue}
156
</div>
157
);
158
};
159
160
// Status badge formatter
161
const StatusFormatter = ({ value }) => {
162
const getStatusColor = (status) => {
163
switch (status) {
164
case 'active': return '#28a745';
165
case 'inactive': return '#dc3545';
166
case 'pending': return '#ffc107';
167
default: return '#6c757d';
168
}
169
};
170
171
return (
172
<span
173
style={{
174
padding: '4px 8px',
175
borderRadius: '4px',
176
backgroundColor: getStatusColor(value),
177
color: 'white',
178
fontSize: '12px',
179
fontWeight: 'bold'
180
}}
181
>
182
{value || 'unknown'}
183
</span>
184
);
185
};
186
187
// Progress bar formatter
188
const ProgressFormatter = ({ value }) => {
189
const percentage = Math.max(0, Math.min(100, value || 0));
190
191
return (
192
<div style={{ width: '100%', backgroundColor: '#e9ecef', borderRadius: '4px' }}>
193
<div
194
style={{
195
width: `${percentage}%`,
196
height: '20px',
197
backgroundColor: '#007bff',
198
borderRadius: '4px',
199
textAlign: 'center',
200
lineHeight: '20px',
201
color: 'white',
202
fontSize: '12px'
203
}}
204
>
205
{percentage}%
206
</div>
207
</div>
208
);
209
};
210
211
// Link formatter
212
const LinkFormatter = ({ value, row }) => {
213
return (
214
<a
215
href={value}
216
target="_blank"
217
rel="noopener noreferrer"
218
style={{ color: '#007bff', textDecoration: 'underline' }}
219
>
220
{row.linkText || 'View'}
221
</a>
222
);
223
};
224
225
// Image formatter
226
const ImageFormatter = ({ value }) => {
227
return value ? (
228
<img
229
src={value}
230
alt="Preview"
231
style={{
232
width: '40px',
233
height: '40px',
234
objectFit: 'cover',
235
borderRadius: '4px'
236
}}
237
/>
238
) : (
239
<div style={{
240
width: '40px',
241
height: '40px',
242
backgroundColor: '#f8f9fa',
243
border: '1px dashed #dee2e6',
244
borderRadius: '4px'
245
}} />
246
);
247
};
248
249
// Usage in columns
250
const columns = [
251
{ key: 'id', name: 'ID' },
252
{ key: 'name', name: 'Name' },
253
{
254
key: 'price',
255
name: 'Price',
256
formatter: <CurrencyFormatter />
257
},
258
{
259
key: 'status',
260
name: 'Status',
261
formatter: <StatusFormatter />
262
},
263
{
264
key: 'progress',
265
name: 'Progress',
266
formatter: <ProgressFormatter />
267
},
268
{
269
key: 'website',
270
name: 'Website',
271
formatter: <LinkFormatter />
272
},
273
{
274
key: 'avatar',
275
name: 'Avatar',
276
formatter: <ImageFormatter />,
277
width: 80
278
}
279
];
280
```
281
282
### Conditional Formatting
283
284
Using formatters with conditional logic based on cell values or row data.
285
286
```javascript
287
// Conditional cell styling formatter
288
const ConditionalFormatter = ({ value, row, column }) => {
289
const getStyle = () => {
290
if (column.key === 'amount' && value < 0) {
291
return { color: 'red', fontWeight: 'bold' };
292
}
293
if (column.key === 'status' && row.priority === 'high') {
294
return { backgroundColor: '#fff3cd', padding: '4px' };
295
}
296
return {};
297
};
298
299
return (
300
<div style={getStyle()}>
301
{value}
302
</div>
303
);
304
};
305
306
// Multi-value formatter
307
const TagsFormatter = ({ value }) => {
308
const tags = Array.isArray(value) ? value : [];
309
310
return (
311
<div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap' }}>
312
{tags.map((tag, index) => (
313
<span
314
key={index}
315
style={{
316
padding: '2px 6px',
317
backgroundColor: '#e9ecef',
318
borderRadius: '12px',
319
fontSize: '11px',
320
color: '#495057'
321
}}
322
>
323
{tag}
324
</span>
325
))}
326
</div>
327
);
328
};
329
330
// Date formatter
331
const DateFormatter = ({ value }) => {
332
if (!value) return null;
333
334
const date = new Date(value);
335
const formattedDate = date.toLocaleDateString('en-US', {
336
year: 'numeric',
337
month: 'short',
338
day: 'numeric'
339
});
340
341
return (
342
<div title={date.toISOString()}>
343
{formattedDate}
344
</div>
345
);
346
};
347
```
348
349
### Formatter Configuration
350
351
Column-level configuration for cell formatting and display.
352
353
```javascript { .api }
354
interface FormattedColumn extends Column {
355
/** Custom formatter component for cell display */
356
formatter?: React.ComponentType<FormatterProps>;
357
/** Additional properties passed to formatter */
358
[key: string]: any;
359
}
360
```
361
362
### Advanced Formatting Patterns
363
364
Complex formatting scenarios with interactive elements and custom styling.
365
366
```javascript
367
// Interactive formatter with buttons
368
const ActionFormatter = ({ value, row, rowIdx }) => {
369
const handleEdit = () => {
370
console.log('Edit row:', rowIdx, row);
371
};
372
373
const handleDelete = () => {
374
console.log('Delete row:', rowIdx, row);
375
};
376
377
return (
378
<div style={{ display: 'flex', gap: '4px' }}>
379
<button
380
onClick={handleEdit}
381
style={{
382
padding: '2px 8px',
383
fontSize: '12px',
384
backgroundColor: '#007bff',
385
color: 'white',
386
border: 'none',
387
borderRadius: '4px',
388
cursor: 'pointer'
389
}}
390
>
391
Edit
392
</button>
393
<button
394
onClick={handleDelete}
395
style={{
396
padding: '2px 8px',
397
fontSize: '12px',
398
backgroundColor: '#dc3545',
399
color: 'white',
400
border: 'none',
401
borderRadius: '4px',
402
cursor: 'pointer'
403
}}
404
>
405
Delete
406
</button>
407
</div>
408
);
409
};
410
411
// Rich content formatter
412
const RichContentFormatter = ({ value, row }) => {
413
return (
414
<div style={{ padding: '4px' }}>
415
<div style={{ fontWeight: 'bold', fontSize: '14px' }}>
416
{row.title}
417
</div>
418
<div style={{ fontSize: '12px', color: '#6c757d' }}>
419
{row.subtitle}
420
</div>
421
<div style={{ fontSize: '11px', marginTop: '2px' }}>
422
{value}
423
</div>
424
</div>
425
);
426
};
427
428
// Sparkline formatter (requires chart library)
429
const SparklineFormatter = ({ value }) => {
430
const data = Array.isArray(value) ? value : [];
431
432
return (
433
<div style={{ width: '100px', height: '30px' }}>
434
{/* Would integrate with chart library like Chart.js or D3 */}
435
<svg width="100" height="30">
436
{data.map((point, index) => (
437
<circle
438
key={index}
439
cx={index * (100 / data.length)}
440
cy={30 - (point * 30)}
441
r="2"
442
fill="#007bff"
443
/>
444
))}
445
</svg>
446
</div>
447
);
448
};
449
```
450
451
### Performance Considerations
452
453
- Formatters are called for every visible cell during rendering
454
- Keep formatter logic lightweight to maintain grid performance
455
- Use React.memo for complex formatters to prevent unnecessary re-renders
456
- Avoid heavy computations or API calls within formatters
457
458
```javascript
459
import React, { memo } from 'react';
460
461
// Optimized formatter with memoization
462
const OptimizedFormatter = memo(({ value, row }) => {
463
const expensiveCalculation = useMemo(() => {
464
return complexCalculation(value);
465
}, [value]);
466
467
return (
468
<div>
469
{expensiveCalculation}
470
</div>
471
);
472
});
473
```