or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-core.mdadvanced.mdauth.mddata-management.mddetail-views.mdforms-inputs.mdi18n.mdindex.mdlayout-navigation.mdlists-data-display.mdui-components.md

detail-views.mddocs/

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.