0
# Detail Views
1
2
React Admin provides comprehensive components for creating, editing, and viewing individual records. These detail view components handle form management, validation, data persistence, and UI layout for single-record operations.
3
4
## Show Component
5
6
The `<Show>` component displays detailed information about a single record in read-only format.
7
8
```typescript { .api }
9
import { Show } from 'react-admin';
10
11
interface ShowProps {
12
id?: Identifier;
13
resource?: string;
14
title?: string | React.ReactElement;
15
actions?: React.ReactElement | false;
16
aside?: React.ReactElement;
17
component?: React.ElementType;
18
className?: string;
19
sx?: any;
20
children: React.ReactNode;
21
emptyWhileLoading?: boolean;
22
queryOptions?: UseQueryOptions;
23
}
24
25
const Show: React.FC<ShowProps>;
26
```
27
28
### Basic Show Usage
29
30
```typescript
31
import { Show, SimpleShowLayout, TextField, DateField, EmailField } from 'react-admin';
32
33
const UserShow = () => (
34
<Show>
35
<SimpleShowLayout>
36
<TextField source="id" />
37
<TextField source="firstName" />
38
<TextField source="lastName" />
39
<EmailField source="email" />
40
<DateField source="createdAt" />
41
</SimpleShowLayout>
42
</Show>
43
);
44
```
45
46
### Show with Custom Actions
47
48
```typescript
49
import { Show, SimpleShowLayout, TopToolbar, EditButton, DeleteButton } from 'react-admin';
50
51
const PostShow = () => {
52
const PostShowActions = () => (
53
<TopToolbar>
54
<EditButton />
55
<DeleteButton />
56
</TopToolbar>
57
);
58
59
return (
60
<Show actions={<PostShowActions />}>
61
<SimpleShowLayout>
62
<TextField source="title" />
63
<TextField source="content" />
64
<DateField source="publishedAt" showTime />
65
<BooleanField source="published" />
66
</SimpleShowLayout>
67
</Show>
68
);
69
};
70
```
71
72
## Edit Component
73
74
The `<Edit>` component provides form-based editing capabilities for existing records.
75
76
```typescript { .api }
77
import { Edit } from 'react-admin';
78
79
interface EditProps {
80
id?: Identifier;
81
resource?: string;
82
title?: string | React.ReactElement;
83
actions?: React.ReactElement | false;
84
aside?: React.ReactElement;
85
component?: React.ElementType;
86
className?: string;
87
sx?: any;
88
children: React.ReactNode;
89
transform?: TransformData;
90
onSuccess?: OnSuccess;
91
onError?: OnError;
92
mutationMode?: MutationMode;
93
mutationOptions?: UseMutationOptions;
94
queryOptions?: UseQueryOptions;
95
redirect?: RedirectToFunction | string | false;
96
disableAuthentication?: boolean;
97
}
98
99
const Edit: React.FC<EditProps>;
100
```
101
102
### Basic Edit Usage
103
104
```typescript
105
import { Edit, SimpleForm, TextInput, BooleanInput, SaveButton } from 'react-admin';
106
107
const PostEdit = () => (
108
<Edit>
109
<SimpleForm>
110
<TextInput source="title" required />
111
<TextInput source="content" multiline rows={4} />
112
<BooleanInput source="published" />
113
<SaveButton />
114
</SimpleForm>
115
</Edit>
116
);
117
```
118
119
### Edit with Validation and Transform
120
121
```typescript
122
import { Edit, SimpleForm, TextInput, required, minLength } from 'react-admin';
123
124
const PostEdit = () => {
125
const transform = (data) => ({
126
...data,
127
slug: data.title?.toLowerCase().replace(/\s+/g, '-'),
128
updatedAt: new Date().toISOString()
129
});
130
131
return (
132
<Edit
133
transform={transform}
134
mutationMode="optimistic"
135
>
136
<SimpleForm>
137
<TextInput
138
source="title"
139
validate={[required(), minLength(5)]}
140
/>
141
<TextInput
142
source="content"
143
validate={required()}
144
multiline
145
rows={6}
146
/>
147
<BooleanInput source="published" />
148
</SimpleForm>
149
</Edit>
150
);
151
};
152
```
153
154
## Create Component
155
156
The `<Create>` component handles creation of new records with form validation and submission.
157
158
```typescript { .api }
159
import { Create } from 'react-admin';
160
161
interface CreateProps {
162
resource?: string;
163
title?: string | React.ReactElement;
164
actions?: React.ReactElement | false;
165
aside?: React.ReactElement;
166
component?: React.ElementType;
167
className?: string;
168
sx?: any;
169
children: React.ReactNode;
170
record?: Partial<RaRecord>;
171
transform?: TransformData;
172
onSuccess?: OnSuccess;
173
onError?: OnError;
174
mutationMode?: MutationMode;
175
mutationOptions?: UseMutationOptions;
176
redirect?: RedirectToFunction | string | false;
177
disableAuthentication?: boolean;
178
}
179
180
const Create: React.FC<CreateProps>;
181
```
182
183
### Basic Create Usage
184
185
```typescript
186
import { Create, SimpleForm, TextInput, BooleanInput, required } from 'react-admin';
187
188
const PostCreate = () => (
189
<Create>
190
<SimpleForm>
191
<TextInput source="title" validate={required()} />
192
<TextInput source="content" multiline rows={4} />
193
<BooleanInput source="published" defaultValue={false} />
194
</SimpleForm>
195
</Create>
196
);
197
```
198
199
### Create with Default Values
200
201
```typescript
202
import { Create, SimpleForm, TextInput, SelectInput } from 'react-admin';
203
204
const PostCreate = () => {
205
const defaultValues = {
206
status: 'draft',
207
author: 'current-user-id',
208
createdAt: new Date().toISOString()
209
};
210
211
return (
212
<Create record={defaultValues}>
213
<SimpleForm>
214
<TextInput source="title" required />
215
<TextInput source="content" multiline rows={4} />
216
<SelectInput
217
source="status"
218
choices={[
219
{ id: 'draft', name: 'Draft' },
220
{ id: 'published', name: 'Published' }
221
]}
222
/>
223
</SimpleForm>
224
</Create>
225
);
226
};
227
```
228
229
## Layout Components
230
231
### SimpleShowLayout
232
233
Basic vertical layout for show views.
234
235
```typescript { .api }
236
import { SimpleShowLayout } from 'react-admin';
237
238
interface SimpleShowLayoutProps {
239
children: React.ReactNode;
240
className?: string;
241
sx?: any;
242
spacing?: number;
243
direction?: 'row' | 'column';
244
}
245
246
const SimpleShowLayout: React.FC<SimpleShowLayoutProps>;
247
```
248
249
### TabbedShowLayout
250
251
Tabbed layout for organizing show fields into sections.
252
253
```typescript { .api }
254
import { TabbedShowLayout, Tab } from 'react-admin';
255
256
interface TabbedShowLayoutProps {
257
children: React.ReactNode;
258
className?: string;
259
sx?: any;
260
tabs?: React.ComponentType;
261
value?: number | string;
262
indicator?: React.ComponentType;
263
}
264
265
const TabbedShowLayout: React.FC<TabbedShowLayoutProps>;
266
267
interface TabProps {
268
label: string;
269
icon?: React.ReactElement;
270
value?: string | number;
271
count?: number;
272
children: React.ReactNode;
273
className?: string;
274
sx?: any;
275
}
276
277
const Tab: React.FC<TabProps>;
278
```
279
280
#### Tabbed Show Example
281
282
```typescript
283
import { Show, TabbedShowLayout, Tab, TextField, DateField, ReferenceManyField, Datagrid } from 'react-admin';
284
285
const UserShow = () => (
286
<Show>
287
<TabbedShowLayout>
288
<Tab label="General">
289
<TextField source="firstName" />
290
<TextField source="lastName" />
291
<EmailField source="email" />
292
<DateField source="createdAt" />
293
</Tab>
294
295
<Tab label="Profile">
296
<TextField source="bio" />
297
<TextField source="website" />
298
<TextField source="location" />
299
</Tab>
300
301
<Tab label="Posts" count={(record) => record.postCount}>
302
<ReferenceManyField reference="posts" target="authorId">
303
<Datagrid>
304
<TextField source="title" />
305
<DateField source="publishedAt" />
306
</Datagrid>
307
</ReferenceManyField>
308
</Tab>
309
</TabbedShowLayout>
310
</Show>
311
);
312
```
313
314
## Form Layout Components
315
316
### SimpleForm
317
318
Basic form layout for edit and create views.
319
320
```typescript { .api }
321
import { SimpleForm } from 'react-admin';
322
323
interface SimpleFormProps {
324
children: React.ReactNode;
325
defaultValues?: any;
326
validate?: ValidateForm;
327
onSubmit?: (data: any) => void | Promise<void>;
328
toolbar?: React.ReactElement | false;
329
warnWhenUnsavedChanges?: boolean;
330
sanitizeEmptyValues?: boolean;
331
className?: string;
332
sx?: any;
333
}
334
335
const SimpleForm: React.FC<SimpleFormProps>;
336
```
337
338
### TabbedForm
339
340
Tabbed form layout for organizing inputs into sections.
341
342
```typescript { .api }
343
import { TabbedForm, FormTab } from 'react-admin';
344
345
interface TabbedFormProps {
346
children: React.ReactNode;
347
defaultValues?: any;
348
validate?: ValidateForm;
349
onSubmit?: (data: any) => void | Promise<void>;
350
toolbar?: React.ReactElement | false;
351
tabs?: React.ComponentType;
352
warnWhenUnsavedChanges?: boolean;
353
sanitizeEmptyValues?: boolean;
354
className?: string;
355
sx?: any;
356
}
357
358
const TabbedForm: React.FC<TabbedFormProps>;
359
360
interface FormTabProps {
361
label: string;
362
icon?: React.ReactElement;
363
value?: string | number;
364
children: React.ReactNode;
365
className?: string;
366
sx?: any;
367
}
368
369
const FormTab: React.FC<FormTabProps>;
370
```
371
372
#### Tabbed Form Example
373
374
```typescript
375
import { Edit, TabbedForm, FormTab, TextInput, NumberInput, BooleanInput } from 'react-admin';
376
377
const ProductEdit = () => (
378
<Edit>
379
<TabbedForm>
380
<FormTab label="General">
381
<TextInput source="name" required fullWidth />
382
<TextInput source="description" multiline rows={4} fullWidth />
383
<NumberInput source="price" required />
384
</FormTab>
385
386
<FormTab label="Inventory">
387
<NumberInput source="stock" required />
388
<NumberInput source="minStock" />
389
<BooleanInput source="trackInventory" />
390
</FormTab>
391
392
<FormTab label="SEO">
393
<TextInput source="metaTitle" fullWidth />
394
<TextInput source="metaDescription" multiline rows={2} fullWidth />
395
<TextInput source="slug" fullWidth />
396
</FormTab>
397
</TabbedForm>
398
</Edit>
399
);
400
```
401
402
## Action Components
403
404
### SaveButton
405
406
Button for saving form data.
407
408
```typescript { .api }
409
import { SaveButton } from 'react-admin';
410
411
interface SaveButtonProps {
412
label?: string;
413
icon?: React.ReactElement;
414
disabled?: boolean;
415
variant?: 'text' | 'outlined' | 'contained';
416
color?: 'inherit' | 'primary' | 'secondary';
417
size?: 'small' | 'medium' | 'large';
418
alwaysEnable?: boolean;
419
transform?: TransformData;
420
mutationOptions?: UseMutationOptions;
421
type?: 'button' | 'submit';
422
className?: string;
423
sx?: any;
424
}
425
426
const SaveButton: React.FC<SaveButtonProps>;
427
```
428
429
### DeleteButton
430
431
Button for deleting records.
432
433
```typescript { .api }
434
import { DeleteButton } from 'react-admin';
435
436
interface DeleteButtonProps {
437
label?: string;
438
icon?: React.ReactElement;
439
disabled?: boolean;
440
className?: string;
441
sx?: any;
442
confirmTitle?: string;
443
confirmContent?: string | React.ReactElement;
444
redirect?: string | false;
445
mutationMode?: MutationMode;
446
mutationOptions?: UseMutationOptions;
447
}
448
449
const DeleteButton: React.FC<DeleteButtonProps>;
450
```
451
452
### EditButton
453
454
Navigation button to edit view.
455
456
```typescript { .api }
457
import { EditButton } from 'react-admin';
458
459
interface EditButtonProps {
460
label?: string;
461
icon?: React.ReactElement;
462
className?: string;
463
sx?: any;
464
record?: RaRecord;
465
resource?: string;
466
}
467
468
const EditButton: React.FC<EditButtonProps>;
469
```
470
471
### ShowButton
472
473
Navigation button to show view.
474
475
```typescript { .api }
476
import { ShowButton } from 'react-admin';
477
478
const ShowButton: React.FC<EditButtonProps>;
479
```
480
481
## Custom Actions and Toolbars
482
483
### Custom Toolbar
484
485
```typescript
486
import { Toolbar, SaveButton, DeleteButton } from 'react-admin';
487
488
const PostEditToolbar = () => (
489
<Toolbar>
490
<SaveButton />
491
<SaveButton
492
label="Save and Continue"
493
transform={data => ({ ...data, continueEditing: true })}
494
variant="outlined"
495
/>
496
<DeleteButton />
497
</Toolbar>
498
);
499
500
const PostEdit = () => (
501
<Edit>
502
<SimpleForm toolbar={<PostEditToolbar />}>
503
<TextInput source="title" />
504
<TextInput source="content" multiline />
505
</SimpleForm>
506
</Edit>
507
);
508
```
509
510
### Custom Actions
511
512
```typescript
513
import { TopToolbar, Button, useRecordContext, useRedirect, useNotify } from 'react-admin';
514
515
const PostShowActions = () => {
516
const record = useRecordContext();
517
const redirect = useRedirect();
518
const notify = useNotify();
519
520
const handleClone = () => {
521
redirect('create', 'posts', undefined, undefined, {
522
record: { ...record, id: undefined, title: `Copy of ${record.title}` }
523
});
524
notify('Ready to create a copy');
525
};
526
527
return (
528
<TopToolbar>
529
<EditButton />
530
<Button label="Clone" onClick={handleClone} />
531
<DeleteButton />
532
</TopToolbar>
533
);
534
};
535
```
536
537
## Validation in Detail Views
538
539
### Form-Level Validation
540
541
```typescript
542
import { Edit, SimpleForm, TextInput } from 'react-admin';
543
544
const validatePost = (values) => {
545
const errors: any = {};
546
547
if (!values.title) {
548
errors.title = 'Title is required';
549
} else if (values.title.length < 5) {
550
errors.title = 'Title must be at least 5 characters';
551
}
552
553
if (!values.content) {
554
errors.content = 'Content is required';
555
}
556
557
if (values.publishedAt && new Date(values.publishedAt) > new Date()) {
558
errors.publishedAt = 'Publication date cannot be in the future';
559
}
560
561
return errors;
562
};
563
564
const PostEdit = () => (
565
<Edit>
566
<SimpleForm validate={validatePost}>
567
<TextInput source="title" />
568
<TextInput source="content" multiline />
569
<DateTimeInput source="publishedAt" />
570
</SimpleForm>
571
</Edit>
572
);
573
```
574
575
### Async Validation
576
577
```typescript
578
const asyncValidatePost = async (values) => {
579
const errors: any = {};
580
581
if (values.slug) {
582
const response = await fetch(`/api/check-slug?slug=${values.slug}`);
583
const result = await response.json();
584
585
if (!result.available) {
586
errors.slug = 'This slug is already taken';
587
}
588
}
589
590
return errors;
591
};
592
```
593
594
## Side Effects and Hooks
595
596
### Redirect After Success
597
598
```typescript
599
import { Edit, SimpleForm, useRedirect, useNotify } from 'react-admin';
600
601
const PostEdit = () => {
602
const redirect = useRedirect();
603
const notify = useNotify();
604
605
const handleSuccess = (data) => {
606
notify('Post updated successfully');
607
if (data.published) {
608
redirect('list', 'posts');
609
} else {
610
redirect('show', 'posts', data.id);
611
}
612
};
613
614
return (
615
<Edit onSuccess={handleSuccess}>
616
<SimpleForm>
617
<TextInput source="title" />
618
<BooleanInput source="published" />
619
</SimpleForm>
620
</Edit>
621
);
622
};
623
```
624
625
### Transform Data Before Save
626
627
```typescript
628
import { Edit, SimpleForm, TextInput } from 'react-admin';
629
630
const PostEdit = () => {
631
const transform = (data) => ({
632
...data,
633
slug: data.title?.toLowerCase()
634
.replace(/[^\w ]+/g, '')
635
.replace(/ +/g, '-'),
636
updatedAt: new Date().toISOString(),
637
wordCount: data.content?.split(' ').length || 0
638
});
639
640
return (
641
<Edit transform={transform}>
642
<SimpleForm>
643
<TextInput source="title" />
644
<TextInput source="content" multiline />
645
</SimpleForm>
646
</Edit>
647
);
648
};
649
```
650
651
## Error Handling
652
653
### Custom Error Display
654
655
```typescript
656
import { Edit, SimpleForm, useNotify } from 'react-admin';
657
658
const PostEdit = () => {
659
const notify = useNotify();
660
661
const handleError = (error) => {
662
if (error.status === 403) {
663
notify('You do not have permission to edit this post', { type: 'error' });
664
} else if (error.status === 409) {
665
notify('This post has been modified by another user', { type: 'error' });
666
} else {
667
notify('An error occurred while saving', { type: 'error' });
668
}
669
};
670
671
return (
672
<Edit onError={handleError}>
673
<SimpleForm>
674
<TextInput source="title" />
675
<TextInput source="content" multiline />
676
</SimpleForm>
677
</Edit>
678
);
679
};
680
```
681
682
## Advanced Examples
683
684
### Conditional Fields in Forms
685
686
```typescript
687
import { Edit, TabbedForm, FormTab, FormDataConsumer, BooleanInput, TextInput } from 'react-admin';
688
689
const ProductEdit = () => (
690
<Edit>
691
<TabbedForm>
692
<FormTab label="General">
693
<TextInput source="name" fullWidth />
694
<BooleanInput source="hasVariants" />
695
696
<FormDataConsumer>
697
{({ formData, ...rest }) =>
698
formData.hasVariants && (
699
<TextInput
700
source="variantOptions"
701
label="Variant Options (comma separated)"
702
fullWidth
703
{...rest}
704
/>
705
)
706
}
707
</FormDataConsumer>
708
</FormTab>
709
</TabbedForm>
710
</Edit>
711
);
712
```
713
714
### Master-Detail Views
715
716
```typescript
717
import { Show, TabbedShowLayout, Tab, ReferenceManyField, Datagrid, CreateButton } from 'react-admin';
718
719
const OrderShow = () => (
720
<Show>
721
<TabbedShowLayout>
722
<Tab label="Order Info">
723
<TextField source="orderNumber" />
724
<DateField source="orderDate" />
725
<TextField source="status" />
726
<NumberField source="total" options={{ style: 'currency', currency: 'USD' }} />
727
</Tab>
728
729
<Tab label="Items">
730
<ReferenceManyField
731
reference="orderItems"
732
target="orderId"
733
label="Order Items"
734
>
735
<Datagrid>
736
<TextField source="productName" />
737
<NumberField source="quantity" />
738
<NumberField source="price" options={{ style: 'currency', currency: 'USD' }} />
739
<NumberField source="total" options={{ style: 'currency', currency: 'USD' }} />
740
</Datagrid>
741
</ReferenceManyField>
742
</Tab>
743
</TabbedShowLayout>
744
</Show>
745
);
746
```
747
748
### Aside Panels
749
750
```typescript
751
import { Edit, SimpleForm, Card, CardContent, Typography } from 'react-admin';
752
753
const PostAside = () => (
754
<Card sx={{ width: 300, margin: 2 }}>
755
<CardContent>
756
<Typography variant="h6">Publication Tips</Typography>
757
<Typography variant="body2">
758
• Keep titles under 60 characters for SEO
759
• Use engaging opening paragraphs
760
• Include relevant tags
761
• Preview before publishing
762
</Typography>
763
</CardContent>
764
</Card>
765
);
766
767
const PostEdit = () => (
768
<Edit aside={<PostAside />}>
769
<SimpleForm>
770
<TextInput source="title" fullWidth />
771
<TextInput source="content" multiline rows={10} fullWidth />
772
<ReferenceArrayInput source="tagIds" reference="tags">
773
<AutocompleteInput optionText="name" />
774
</ReferenceArrayInput>
775
</SimpleForm>
776
</Edit>
777
);
778
```
779
780
React Admin's detail view system provides comprehensive functionality for creating sophisticated single-record interfaces with flexible layouts, powerful form handling, and extensive customization options for complex data management scenarios.