0
# Data Display Components
1
2
@mantine/core provides comprehensive components for displaying and organizing data in various formats. These components handle structured data presentation, visual elements, and content organization with accessibility and responsive design built-in.
3
4
## Table
5
6
Comprehensive table component with responsive design and accessibility features.
7
8
```typescript { .api }
9
interface TableProps {
10
/** Table data */
11
data?: TableData;
12
/** Table children */
13
children?: React.ReactNode;
14
/** Table caption */
15
captionSide?: 'top' | 'bottom';
16
/** If true, table will have striped rows */
17
striped?: boolean;
18
/** If true, table rows will have hover effect */
19
highlightOnHover?: boolean;
20
/** If true, table will have border */
21
withTableBorder?: boolean;
22
/** If true, table will have border between columns */
23
withColumnBorders?: boolean;
24
/** If true, table will have border between rows */
25
withRowBorders?: boolean;
26
/** Table layout */
27
layout?: 'auto' | 'fixed';
28
/** Horizontal spacing */
29
horizontalSpacing?: MantineSpacing;
30
/** Vertical spacing */
31
verticalSpacing?: MantineSpacing;
32
/** Font size */
33
fontSize?: MantineSize;
34
}
35
36
interface TableTheadProps {
37
/** Thead children */
38
children: React.ReactNode;
39
}
40
41
interface TableTbodyProps {
42
/** Tbody children */
43
children: React.ReactNode;
44
}
45
46
interface TableTfootProps {
47
/** Tfoot children */
48
children: React.ReactNode;
49
}
50
51
interface TableTrProps {
52
/** Tr children */
53
children: React.ReactNode;
54
/** If true, row will have hover effect */
55
hover?: boolean;
56
}
57
58
interface TableThProps {
59
/** Th children */
60
children?: React.ReactNode;
61
/** Column width */
62
w?: React.CSSProperties['width'];
63
/** Column min width */
64
miw?: React.CSSProperties['minWidth'];
65
/** Text align */
66
ta?: React.CSSProperties['textAlign'];
67
}
68
69
interface TableTdProps {
70
/** Td children */
71
children?: React.ReactNode;
72
/** Cell width */
73
w?: React.CSSProperties['width'];
74
/** Cell min width */
75
miw?: React.CSSProperties['minWidth'];
76
/** Text align */
77
ta?: React.CSSProperties['textAlign'];
78
}
79
80
interface TableCaptionProps {
81
/** Caption children */
82
children: React.ReactNode;
83
}
84
85
interface TableScrollContainerProps {
86
/** Container children */
87
children: React.ReactNode;
88
/** Minimum width before scrolling */
89
minWidth?: React.CSSProperties['minWidth'];
90
/** Scroll container type */
91
type?: 'native' | 'scrollarea';
92
}
93
94
interface TableData {
95
/** Table caption */
96
caption?: string;
97
/** Table head data */
98
head?: string[];
99
/** Table body data */
100
body?: string[][];
101
/** Table foot data */
102
foot?: string[];
103
}
104
```
105
106
**Usage Example:**
107
108
```tsx
109
import { Table } from '@mantine/core';
110
111
const elements = [
112
{ position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' },
113
{ position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' },
114
{ position: 39, mass: 88.906, symbol: 'Y', name: 'Yttrium' },
115
{ position: 56, mass: 137.33, symbol: 'Ba', name: 'Barium' },
116
{ position: 58, mass: 140.12, symbol: 'Ce', name: 'Cerium' },
117
];
118
119
function TableDemo() {
120
const rows = elements.map((element) => (
121
<Table.Tr key={element.name}>
122
<Table.Td>{element.position}</Table.Td>
123
<Table.Td>{element.name}</Table.Td>
124
<Table.Td>{element.symbol}</Table.Td>
125
<Table.Td>{element.mass}</Table.Td>
126
</Table.Tr>
127
));
128
129
return (
130
<Table>
131
<Table.Thead>
132
<Table.Tr>
133
<Table.Th>Element position</Table.Th>
134
<Table.Th>Element name</Table.Th>
135
<Table.Th>Symbol</Table.Th>
136
<Table.Th>Atomic mass</Table.Th>
137
</Table.Tr>
138
</Table.Thead>
139
<Table.Tbody>{rows}</Table.Tbody>
140
</Table>
141
);
142
}
143
144
// Table with data prop
145
function TableWithData() {
146
return (
147
<Table
148
data={{
149
head: ['Element position', 'Element name', 'Symbol', 'Atomic mass'],
150
body: [
151
[6, 'Carbon', 'C', 12.011],
152
[7, 'Nitrogen', 'N', 14.007],
153
[39, 'Yttrium', 'Y', 88.906],
154
[56, 'Barium', 'Ba', 137.33],
155
[58, 'Cerium', 'Ce', 140.12],
156
],
157
}}
158
/>
159
);
160
}
161
162
// Responsive table with scroll container
163
function ResponsiveTable() {
164
return (
165
<Table.ScrollContainer minWidth={800}>
166
<Table>
167
{/* Table content */}
168
</Table>
169
</Table.ScrollContainer>
170
);
171
}
172
```
173
174
## List
175
176
Ordered and unordered list component with custom styling options.
177
178
```typescript { .api }
179
interface ListProps {
180
/** List type */
181
type?: 'ordered' | 'unordered';
182
/** List children */
183
children: React.ReactNode;
184
/** If true, list will have spacing between items */
185
withPadding?: boolean;
186
/** List icon */
187
icon?: React.ReactNode;
188
/** List spacing */
189
spacing?: MantineSpacing;
190
/** List item spacing */
191
size?: MantineSize;
192
/** If true, list will be centered */
193
center?: boolean;
194
}
195
196
interface ListItemProps {
197
/** Item children */
198
children: React.ReactNode;
199
/** Item icon */
200
icon?: React.ReactNode;
201
}
202
```
203
204
**Usage Example:**
205
206
```tsx
207
import { List, ThemeIcon } from '@mantine/core';
208
209
function ListDemo() {
210
return (
211
<List>
212
<List.Item>Clone or download repository from GitHub</List.Item>
213
<List.Item>Install dependencies with yarn or npm</List.Item>
214
<List.Item>To start development server run npm start command</List.Item>
215
<List.Item>Run tests to make sure your changes do not break the build</List.Item>
216
</List>
217
);
218
}
219
220
// Custom icons
221
function ListWithIcons() {
222
return (
223
<List
224
spacing="xs"
225
size="sm"
226
center
227
icon={
228
<ThemeIcon color="teal" size={24} radius="xl">
229
β
230
</ThemeIcon>
231
}
232
>
233
<List.Item>Clone or download repository from GitHub</List.Item>
234
<List.Item>Install dependencies with yarn or npm</List.Item>
235
<List.Item>To start development server run npm start command</List.Item>
236
</List>
237
);
238
}
239
240
// Different item icons
241
function ListWithDifferentIcons() {
242
return (
243
<List spacing="xs" size="sm">
244
<List.Item
245
icon={
246
<ThemeIcon color="blue" size={24} radius="xl">
247
1
248
</ThemeIcon>
249
}
250
>
251
First item
252
</List.Item>
253
<List.Item
254
icon={
255
<ThemeIcon color="red" size={24} radius="xl">
256
2
257
</ThemeIcon>
258
}
259
>
260
Second item
261
</List.Item>
262
</List>
263
);
264
}
265
```
266
267
## Tree
268
269
Tree view component for hierarchical data display.
270
271
```typescript { .api }
272
interface TreeProps {
273
/** Tree data */
274
data: TreeNodeData[];
275
/** Level offset in px */
276
levelOffset?: number;
277
/** Expand on click */
278
expandOnClick?: boolean;
279
/** Tree selection mode */
280
selectOnClick?: boolean;
281
/** Clear selection on outside click */
282
clearSelectionOnOutsideClick?: boolean;
283
/** Selected node value */
284
selectedState?: [string[], (value: string[]) => void];
285
/** Expanded nodes */
286
expandedState?: [string[], (value: string[]) => void];
287
/** Called when node is selected */
288
onNodeSelect?: (node: TreeNodeData) => void;
289
/** Called when node is expanded/collapsed */
290
onNodeExpand?: (node: TreeNodeData) => void;
291
/** Render node function */
292
renderNode?: (payload: {
293
node: TreeNodeData;
294
expanded: boolean;
295
selected: boolean;
296
elementProps: React.ComponentPropsWithoutRef<'div'>;
297
}) => React.ReactNode;
298
}
299
300
interface TreeNodeData {
301
/** Node value, must be unique */
302
value: string;
303
/** Node label */
304
label: React.ReactNode;
305
/** Node children */
306
children?: TreeNodeData[];
307
/** If true, node cannot be selected */
308
disabled?: boolean;
309
/** Node data for custom rendering */
310
nodeProps?: Record<string, any>;
311
}
312
```
313
314
**Usage Example:**
315
316
```tsx
317
import { Tree } from '@mantine/core';
318
319
const data = [
320
{
321
value: 'src',
322
label: 'src',
323
children: [
324
{
325
value: 'components',
326
label: 'components',
327
children: [
328
{ value: 'Accordion.tsx', label: 'Accordion.tsx' },
329
{ value: 'Tree.tsx', label: 'Tree.tsx' },
330
{ value: 'Button.tsx', label: 'Button.tsx' },
331
],
332
},
333
{ value: 'hooks', label: 'hooks' },
334
{ value: 'utils', label: 'utils' },
335
],
336
},
337
{
338
value: 'package.json',
339
label: 'package.json',
340
},
341
{
342
value: 'tsconfig.json',
343
label: 'tsconfig.json',
344
},
345
];
346
347
function TreeDemo() {
348
return <Tree data={data} />;
349
}
350
```
351
352
## Timeline
353
354
Timeline component for displaying chronological events.
355
356
```typescript { .api }
357
interface TimelineProps {
358
/** Timeline children (Timeline.Item components) */
359
children: React.ReactNode;
360
/** Timeline orientation */
361
active?: number;
362
/** Timeline color */
363
color?: MantineColor;
364
/** Timeline radius */
365
radius?: MantineRadius;
366
/** Bullet size */
367
bulletSize?: number;
368
/** Line width */
369
lineWidth?: number;
370
/** If true, timeline will be reversed */
371
reverseActive?: boolean;
372
}
373
374
interface TimelineItemProps {
375
/** Item children */
376
children?: React.ReactNode;
377
/** Item bullet */
378
bullet?: React.ReactNode;
379
/** Item title */
380
title?: React.ReactNode;
381
/** Item color */
382
color?: MantineColor;
383
/** Bullet size */
384
bulletSize?: number;
385
/** Line variant */
386
lineVariant?: 'solid' | 'dashed' | 'dotted';
387
/** If true, item bullet will be hollow */
388
radius?: MantineRadius;
389
}
390
```
391
392
**Usage Example:**
393
394
```tsx
395
import { Timeline, Text } from '@mantine/core';
396
397
function TimelineDemo() {
398
return (
399
<Timeline active={1} bulletSize={24} lineWidth={2}>
400
<Timeline.Item bullet="π§" title="New email">
401
<Text color="dimmed" size="sm">You've got new email from Kristina Groves</Text>
402
<Text size="xs" mt={4}>2 minutes ago</Text>
403
</Timeline.Item>
404
405
<Timeline.Item bullet="π±" title="Another notification">
406
<Text color="dimmed" size="sm">You've got new message from Sarah Johnson</Text>
407
<Text size="xs" mt={4}>5 minutes ago</Text>
408
</Timeline.Item>
409
410
<Timeline.Item title="Bug fix" bullet="π" lineVariant="dashed">
411
<Text color="dimmed" size="sm">You've fixed a bug</Text>
412
<Text size="xs" mt={4}>10 minutes ago</Text>
413
</Timeline.Item>
414
415
<Timeline.Item title="User left a comment" bullet="π¬">
416
<Text color="dimmed" size="sm">You've got a comment from Robert</Text>
417
<Text size="xs" mt={4}>12 minutes ago</Text>
418
</Timeline.Item>
419
</Timeline>
420
);
421
}
422
```
423
424
## Card
425
426
Container component for grouping related content with optional sections.
427
428
```typescript { .api }
429
interface CardProps {
430
/** Card children */
431
children: React.ReactNode;
432
/** Card padding */
433
padding?: MantineSpacing;
434
/** Card radius */
435
radius?: MantineRadius;
436
/** If true, card will have border */
437
withBorder?: boolean;
438
/** Card shadow */
439
shadow?: MantineShadow;
440
}
441
442
interface CardSectionProps {
443
/** Section children */
444
children: React.ReactNode;
445
/** If true, section will inherit card padding */
446
inheritPadding?: boolean;
447
/** If true, section will have border */
448
withBorder?: boolean;
449
/** Section padding */
450
p?: MantineSpacing;
451
/** Section margin */
452
m?: MantineSpacing;
453
}
454
```
455
456
**Usage Example:**
457
458
```tsx
459
import { Card, Image, Text, Badge, Button, Group } from '@mantine/core';
460
461
function CardDemo() {
462
return (
463
<Card shadow="sm" padding="lg" radius="md" withBorder>
464
<Card.Section>
465
<Image
466
src="https://images.unsplash.com/photo-1527004013197-933c4bb611b3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=720&q=80"
467
height={160}
468
alt="Norway"
469
/>
470
</Card.Section>
471
472
<Group justify="space-between" mt="md" mb="xs">
473
<Text fw={500}>Norway Fjord Adventures</Text>
474
<Badge color="pink" variant="light">
475
On Sale
476
</Badge>
477
</Group>
478
479
<Text size="sm" c="dimmed">
480
With Fjord Tours you can explore more of the magical fjord landscapes with tours and
481
activities on and around the fjords of Norway
482
</Text>
483
484
<Button color="blue" fullWidth mt="md" radius="md">
485
Book classic tour now
486
</Button>
487
</Card>
488
);
489
}
490
```
491
492
## Paper
493
494
Simple container component with background color and optional shadow/border.
495
496
```typescript { .api }
497
interface PaperProps {
498
/** Paper children */
499
children?: React.ReactNode;
500
/** Paper shadow */
501
shadow?: MantineShadow;
502
/** Paper padding */
503
p?: MantineSpacing;
504
/** Paper radius */
505
radius?: MantineRadius;
506
/** If true, paper will have border */
507
withBorder?: boolean;
508
}
509
```
510
511
**Usage Example:**
512
513
```tsx
514
import { Paper, Text } from '@mantine/core';
515
516
function PaperDemo() {
517
return (
518
<Paper shadow="xs" p="md">
519
<Text>Paper is the most basic ui component</Text>
520
</Paper>
521
);
522
}
523
```
524
525
## Badge
526
527
Small status or category indicator component.
528
529
```typescript { .api }
530
interface BadgeProps {
531
/** Badge children */
532
children: React.ReactNode;
533
/** Badge variant */
534
variant?: 'light' | 'filled' | 'outline' | 'dot' | 'transparent';
535
/** Badge size */
536
size?: MantineSize;
537
/** Badge radius */
538
radius?: MantineRadius;
539
/** Badge color */
540
color?: MantineColor;
541
/** Badge left section */
542
leftSection?: React.ReactNode;
543
/** Badge right section */
544
rightSection?: React.ReactNode;
545
/** If true, badge will take full width of container */
546
fullWidth?: boolean;
547
}
548
```
549
550
**Usage Example:**
551
552
```tsx
553
import { Badge, Group } from '@mantine/core';
554
555
function BadgeDemo() {
556
return (
557
<Group>
558
<Badge variant="light">Default</Badge>
559
<Badge variant="filled">Filled</Badge>
560
<Badge variant="outline">Outline</Badge>
561
<Badge variant="dot">Dot</Badge>
562
<Badge leftSection="π§" rightSection="5">
563
With sections
564
</Badge>
565
</Group>
566
);
567
}
568
```
569
570
## ThemeIcon
571
572
Icon wrapper component with theme-based styling.
573
574
```typescript { .api }
575
interface ThemeIconProps {
576
/** Icon children */
577
children: React.ReactNode;
578
/** Icon size */
579
size?: MantineSize | number;
580
/** Icon radius */
581
radius?: MantineRadius;
582
/** Icon variant */
583
variant?: 'filled' | 'light' | 'outline' | 'transparent' | 'white' | 'subtle';
584
/** Icon color */
585
color?: MantineColor;
586
/** Icon gradient (only for gradient variant) */
587
gradient?: MantineGradient;
588
/** If true, icon will auto adjust contrast */
589
autoContrast?: boolean;
590
}
591
```
592
593
**Usage Example:**
594
595
```tsx
596
import { ThemeIcon, Group } from '@mantine/core';
597
598
function ThemeIconDemo() {
599
return (
600
<Group>
601
<ThemeIcon variant="filled" size="lg">
602
π§
603
</ThemeIcon>
604
<ThemeIcon variant="light" color="red">
605
β€οΈ
606
</ThemeIcon>
607
<ThemeIcon variant="outline" color="teal">
608
β
609
</ThemeIcon>
610
<ThemeIcon variant="transparent">
611
π
612
</ThemeIcon>
613
</Group>
614
);
615
}
616
```
617
618
## Avatar
619
620
User avatar component with fallback and group support.
621
622
```typescript { .api }
623
interface AvatarProps {
624
/** Avatar image src */
625
src?: string | null;
626
/** Avatar alt text */
627
alt?: string;
628
/** Avatar radius */
629
radius?: MantineRadius;
630
/** Avatar size */
631
size?: MantineSize | number;
632
/** Avatar variant */
633
variant?: 'filled' | 'light' | 'outline' | 'transparent' | 'white';
634
/** Avatar color */
635
color?: MantineColor;
636
/** Avatar children (displayed when no image) */
637
children?: React.ReactNode;
638
/** Image props */
639
imageProps?: Record<string, any>;
640
}
641
642
interface AvatarGroupProps {
643
/** Group children */
644
children: React.ReactNode;
645
/** Space between avatars */
646
spacing?: MantineSpacing | number;
647
}
648
```
649
650
**Usage Example:**
651
652
```tsx
653
import { Avatar, Group } from '@mantine/core';
654
655
function AvatarDemo() {
656
return (
657
<Group>
658
<Avatar
659
src="https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=255&q=80"
660
alt="User Avatar"
661
/>
662
<Avatar color="cyan" radius="xl">MK</Avatar>
663
<Avatar color="blue">+5</Avatar>
664
</Group>
665
);
666
}
667
668
// Avatar group
669
function AvatarGroupDemo() {
670
return (
671
<Avatar.Group spacing="sm">
672
<Avatar src="image1.png" radius="xl" />
673
<Avatar src="image2.png" radius="xl" />
674
<Avatar src="image3.png" radius="xl" />
675
<Avatar radius="xl">+5</Avatar>
676
</Avatar.Group>
677
);
678
}
679
```
680
681
## Image
682
683
Enhanced image component with loading states and fallbacks.
684
685
```typescript { .api }
686
interface ImageProps {
687
/** Image src */
688
src?: string | null;
689
/** Image alt text */
690
alt?: string;
691
/** Image width */
692
w?: React.CSSProperties['width'];
693
/** Image height */
694
h?: React.CSSProperties['height'];
695
/** Image fit */
696
fit?: React.CSSProperties['objectFit'];
697
/** Image radius */
698
radius?: MantineRadius;
699
/** Fallback component */
700
fallbackSrc?: string;
701
/** Called when image fails to load */
702
onError?: () => void;
703
/** Called when image loads */
704
onLoad?: () => void;
705
}
706
```
707
708
**Usage Example:**
709
710
```tsx
711
import { Image } from '@mantine/core';
712
713
function ImageDemo() {
714
return (
715
<Image
716
radius="md"
717
h={200}
718
src="https://images.unsplash.com/photo-1511216335778-7cb8f49fa7a3?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=720&q=80"
719
alt="Random image"
720
fallbackSrc="https://placehold.co/600x400?text=Fallback"
721
/>
722
);
723
}
724
```
725
726
## ColorSwatch
727
728
Small color sample display component.
729
730
```typescript { .api }
731
interface ColorSwatchProps {
732
/** Swatch color */
733
color: string;
734
/** Swatch size */
735
size?: number;
736
/** Swatch radius */
737
radius?: MantineRadius;
738
/** If true, swatch will have border */
739
withShadow?: boolean;
740
/** Called when swatch is clicked */
741
onClick?: () => void;
742
/** Swatch children */
743
children?: React.ReactNode;
744
}
745
```
746
747
**Usage Example:**
748
749
```tsx
750
import { ColorSwatch, Group } from '@mantine/core';
751
752
function ColorSwatchDemo() {
753
return (
754
<Group>
755
<ColorSwatch color="#ff6b6b" />
756
<ColorSwatch color="#4ecdc4" />
757
<ColorSwatch color="#45b7d1" />
758
<ColorSwatch color="#96ceb4" size={50} />
759
<ColorSwatch color="#feca57" radius="xs" withShadow />
760
</Group>
761
);
762
}
763
```
764
765
## Divider
766
767
Content separator component with optional labels.
768
769
```typescript { .api }
770
interface DividerProps {
771
/** Divider color */
772
color?: MantineColor;
773
/** Divider orientation */
774
orientation?: 'horizontal' | 'vertical';
775
/** Divider size */
776
size?: MantineSize | number;
777
/** Divider variant */
778
variant?: 'solid' | 'dashed' | 'dotted';
779
/** Divider label */
780
label?: React.ReactNode;
781
/** Label position */
782
labelPosition?: 'left' | 'center' | 'right';
783
}
784
```
785
786
**Usage Example:**
787
788
```tsx
789
import { Divider, Text } from '@mantine/core';
790
791
function DividerDemo() {
792
return (
793
<div>
794
<Text>
795
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
796
</Text>
797
798
<Divider my="sm" />
799
800
<Text>
801
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.
802
</Text>
803
804
<Divider my="sm" variant="dashed" />
805
806
<Text>
807
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum.
808
</Text>
809
810
<Divider
811
my="xs"
812
label="Label on the left"
813
labelPosition="left"
814
/>
815
816
<Divider
817
my="xs"
818
label="Label in the center"
819
labelPosition="center"
820
/>
821
822
<Divider
823
my="xs"
824
label="Label on the right"
825
labelPosition="right"
826
/>
827
</div>
828
);
829
}
830
```
831
832
## Spoiler
833
834
Collapsible content component with show more/less functionality.
835
836
```typescript { .api }
837
interface SpoilerProps {
838
/** Spoiler children */
839
children: React.ReactNode;
840
/** Maximum height when collapsed */
841
maxHeight: number;
842
/** Show label */
843
showLabel?: React.ReactNode;
844
/** Hide label */
845
hideLabel?: React.ReactNode;
846
/** Transition duration */
847
transitionDuration?: number;
848
/** Called when spoiler state changes */
849
onExpandedChange?: (expanded: boolean) => void;
850
/** If true, spoiler is controlled */
851
expanded?: boolean;
852
/** Default expanded state */
853
defaultExpanded?: boolean;
854
}
855
```
856
857
**Usage Example:**
858
859
```tsx
860
import { Spoiler } from '@mantine/core';
861
862
function SpoilerDemo() {
863
return (
864
<Spoiler maxHeight={120} showLabel="Show more" hideLabel="Hide">
865
{/* Long content that will be collapsed */}
866
Lorem ipsum dolor sit amet consectetur adipisicing elit. Unde
867
provident eos fugiat id necessitatibus magni ducimus molestias. Placeat
868
consectetur consequuntur quod voluptatum perspiciatis repellat
869
consequatur, maxime mollitia, illo rerum sunt debitis aliquam in
870
inventore facere obcaecati harum vero molestias distinctio eaque.
871
Aspernatur corporis soluta dicta temporibus. Enim quia voluptatum
872
consequatur fugiat eos, distinctio excepturi amet est! Aut corporis
873
veritatis laboriosam distinctio stone unde aliquam minima. Modi
874
consectetur tempore maiores esse dolorum nemo voluptatum culpa
875
voluptatem non facilis eligendi explicabo quis vel, placeat quasi
876
dignissimos. Voluptatibus laudantium distinctio reiciendis eius ex
877
aliquid quis sit dolor eum reprehenderit quae placeat provident
878
mollitia eos aliquam quibusdam sapiente aperiam accusamus non velit,
879
illo quam eaque!
880
</Spoiler>
881
);
882
}
883
```
884
885
## AspectRatio
886
887
Container that maintains aspect ratio of its content.
888
889
```typescript { .api }
890
interface AspectRatioProps {
891
/** Aspect ratio */
892
ratio: number;
893
/** Container children */
894
children: React.ReactNode;
895
}
896
```
897
898
**Usage Example:**
899
900
```tsx
901
import { AspectRatio } from '@mantine/core';
902
903
function AspectRatioDemo() {
904
return (
905
<AspectRatio ratio={16 / 9}>
906
<iframe
907
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3024.1399415657293!2d-74.00369368459418!3d40.741895479327494!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89c259a9b3117469%3A0xd134e199a405a163!2sEmpire%20State%20Building!5e0!3m2!1sen!2sus!4v1616590069614!5m2!1sen!2sus"
908
title="Google map"
909
style={{ border: 0 }}
910
/>
911
</AspectRatio>
912
);
913
}
914
```
915
916
## Indicator
917
918
Badge overlay component for showing notifications or status.
919
920
```typescript { .api }
921
interface IndicatorProps {
922
/** Indicator children (element to add indicator to) */
923
children: React.ReactNode;
924
/** Indicator content */
925
label?: React.ReactNode;
926
/** Indicator size */
927
size?: number;
928
/** Indicator radius */
929
radius?: MantineRadius;
930
/** Indicator color */
931
color?: MantineColor;
932
/** Indicator position */
933
position?: 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';
934
/** Indicator offset */
935
offset?: number;
936
/** If true, indicator will be disabled */
937
disabled?: boolean;
938
/** If true, indicator will not render when label is empty */
939
showZero?: boolean;
940
/** If true, indicator will have dot style */
941
dot?: boolean;
942
/** If true, indicator will be inline */
943
inline?: boolean;
944
/** Processing animation */
945
processing?: boolean;
946
/** If true, indicator will have border */
947
withBorder?: boolean;
948
}
949
```
950
951
**Usage Example:**
952
953
```tsx
954
import { Indicator, Avatar, Button, Group } from '@mantine/core';
955
956
function IndicatorDemo() {
957
return (
958
<Group>
959
<Indicator>
960
<Avatar
961
size="lg"
962
src="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=250&q=80"
963
/>
964
</Indicator>
965
966
<Indicator label="New" size={16}>
967
<Avatar
968
size="lg"
969
src="https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=250&q=80"
970
/>
971
</Indicator>
972
973
<Indicator label="99+" inline size={22} color="red">
974
<Button variant="outline">Button</Button>
975
</Indicator>
976
</Group>
977
);
978
}
979
```
980
981
## Pill
982
983
Pill-shaped tag component for labels and selections.
984
985
```typescript { .api }
986
interface PillProps {
987
/** Pill children */
988
children?: React.ReactNode;
989
/** If true, pill will have remove button */
990
withRemoveButton?: boolean;
991
/** Called when remove button is clicked */
992
onRemove?: () => void;
993
/** Remove button aria-label */
994
removeButtonProps?: React.ComponentPropsWithoutRef<'button'>;
995
/** Pill size */
996
size?: MantineSize;
997
}
998
```
999
1000
**Usage Example:**
1001
1002
```tsx
1003
import { Pill, Group } from '@mantine/core';
1004
1005
function PillDemo() {
1006
return (
1007
<Group>
1008
<Pill>React</Pill>
1009
<Pill>Vue</Pill>
1010
<Pill withRemoveButton onRemove={() => console.log('removed')}>
1011
Angular
1012
</Pill>
1013
</Group>
1014
);
1015
}
1016
```
1017
1018
## Theme Integration
1019
1020
Data display components integrate with the Mantine theme system:
1021
1022
```tsx
1023
import { MantineProvider } from '@mantine/core';
1024
1025
const theme = {
1026
components: {
1027
Table: {
1028
defaultProps: {
1029
striped: true,
1030
highlightOnHover: true,
1031
withBorder: true,
1032
},
1033
},
1034
Card: {
1035
defaultProps: {
1036
shadow: 'sm',
1037
radius: 'md',
1038
withBorder: true,
1039
},
1040
},
1041
Badge: {
1042
defaultProps: {
1043
variant: 'light',
1044
size: 'sm',
1045
},
1046
},
1047
},
1048
};
1049
```
1050
1051
## Common Usage Patterns
1052
1053
**Responsive Table:**
1054
```tsx
1055
import { Table, ScrollArea } from '@mantine/core';
1056
1057
function ResponsiveTable({ data }) {
1058
return (
1059
<ScrollArea>
1060
<Table>
1061
<Table.Thead>
1062
<Table.Tr>
1063
{data.headers.map(header => (
1064
<Table.Th key={header}>{header}</Table.Th>
1065
))}
1066
</Table.Tr>
1067
</Table.Thead>
1068
<Table.Tbody>
1069
{data.rows.map(row => (
1070
<Table.Tr key={row.id}>
1071
{row.cells.map(cell => (
1072
<Table.Td key={cell.id}>{cell.value}</Table.Td>
1073
))}
1074
</Table.Tr>
1075
))}
1076
</Table.Tbody>
1077
</Table>
1078
</ScrollArea>
1079
);
1080
}
1081
```
1082
1083
**Data Card Grid:**
1084
```tsx
1085
import { Card, SimpleGrid, Image, Text, Badge, Button } from '@mantine/core';
1086
1087
function DataCardGrid({ items }) {
1088
return (
1089
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }}>
1090
{items.map(item => (
1091
<Card key={item.id} shadow="sm" padding="lg" radius="md" withBorder>
1092
<Card.Section>
1093
<Image src={item.image} height={160} alt={item.title} />
1094
</Card.Section>
1095
1096
<Group justify="space-between" mt="md" mb="xs">
1097
<Text fw={500}>{item.title}</Text>
1098
<Badge color={item.status === 'new' ? 'pink' : 'gray'}>
1099
{item.status}
1100
</Badge>
1101
</Group>
1102
1103
<Text size="sm" c="dimmed">
1104
{item.description}
1105
</Text>
1106
1107
<Button color="blue" fullWidth mt="md" radius="md">
1108
View Details
1109
</Button>
1110
</Card>
1111
))}
1112
</SimpleGrid>
1113
);
1114
}
1115
```