-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
/
Copy pathButtons.md
1646 lines (1223 loc) · 65.9 KB
/
Buttons.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
layout: default
title: "Buttons"
---
# Buttons
React-Admin provides button components for all the common uses.
- **Navigation Buttons**: to navigate between the various react-admin views.
- [`<EditButton>`](#editbutton)
- [`<ShowButton>`](#showbutton)
- [`<CreateButton>`](#createbutton)
- [`<ListButton>`](#listbutton)
- **List Buttons**: to be used in List views.
- [`<ExportButton>`](#exportbutton)
- [`<BulkExportButton>`](#bulkexportbutton)
- [`<BulkDeleteButton>`](#bulkdeletebutton)
- [`<BulkUpdateButton>`](#bulkupdatebutton)
- [`<BulkUpdateFormButton>`](#bulkupdateformbutton)
- [`<FilterButton>`](#filterbutton)
- [`<SelectAllButton>`](#selectallbutton)
- **Record Buttons**: To be used in detail views
- [`<UpdateButton>`](#updatebutton)
- [`<DeleteButton>`](#deletebutton)
- [`<DeleteWithConfirmButton>`](#deletewithconfirmbutton)
- [`<CloneButton>`](#clonebutton)
- **Miscellaneous**
- [`<Button>`](#button)
- [`<RefreshButton>`](#refreshbutton)
- [`<SkipNavigationButton>`](#skipnavigationbutton)
- [`<UserMenu>`](#usermenu)
## `<BulkDeleteButton>`
Deletes the selected rows. To be used inside [the `<Datagrid bulkActionButtons>` prop](./Datagrid.md#bulkactionbuttons) (where it's enabled by default).

### Usage
`<BulkDeleteButton>` reads the current record from `RecordContext`, and the current resource from `ResourceContext`, so in general it doesn’t need any props:
```jsx
import * as React from 'react';
import { Fragment } from 'react';
import { BulkDeleteButton, BulkExportButton } from 'react-admin';
const PostBulkActionButtons = () => (
<Fragment>
<BulkExportButton />
<BulkDeleteButton />
</Fragment>
);
export const PostList = () => (
<List>
<Datagrid bulkActionButtons={<PostBulkActionButtons />}>
...
</Datagrid>
</List>
);
```
### Props
| Prop | Required | Type | Default | Description |
|-------------------|----------|-----------------------------------------|--------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| `confirmContent` | Optional | React node | - | Lets you customize the content of the confirm dialog. Only used in `'pessimistic'` or `'optimistic'` mutation modes |
| `confirmTitle` | Optional | `string` | - | Lets you customize the title of the confirm dialog. Only used in `'pessimistic'` or `'optimistic'` mutation modes |
| `confirmColor` | Optional | <code>'primary' | 'warning'</code> | 'primary' | Lets you customize the color of the confirm dialog's "Confirm" button. Only used in `'pessimistic'` or `'optimistic'` mutation modes |
| `label` | Optional | `string` | 'ra.action.delete' | label or translation message to use |
| `icon` | Optional | `ReactElement` | `<DeleteIcon>` | iconElement, e.g. `<CommentIcon />` |
| `mutationMode` | Optional | `string` | `'undoable'` | Mutation mode (`'undoable'`, `'pessimistic'` or `'optimistic'`) |
| `mutationOptions` | Optional | `object` | null | options for react-query `useMutation` hook |
| `successMessage` | Optional | `string` | 'ra.notification.deleted'| Lets you customize the success notification message. |
**Tip:** If you choose the `'pessimistic'` or `'optimistic'` mutation mode, a confirm dialog will be displayed to the user before the mutation is executed.
### `successMessage`

On success, `<BulkDeleteButton>` displays a "XX elements deleted" notification in English. `<BulkDeleteButton>` uses two successive translation keys to build the success message:
- `resources.{resource}.notifications.deleted` as a first choice
- `ra.notification.deleted` as a fallback
To customize the notification message, you can set custom translation for these keys in your i18nProvider.
**Tip**: If you choose to use a custom translation, be aware that react-admin uses the same translation message for the `<DeleteButton>`, so the message must support [pluralization](./TranslationTranslating.md#interpolation-pluralization-and-default-translation):
```jsx
const englishMessages = {
resources: {
posts: {
notifications: {
deleted: 'Post deleted |||| %{smart_count} postss deleted',
// ...
},
},
},
};
```
Alternately, pass a `successMessage` prop:
```jsx
<BulkDeleteButton successMessage="Posts deleted successfully" />
```
## `<BulkExportButton>`
Same as `<ExportButton>`, except it only exports the selected rows instead of the entire list. To be used inside [the `<Datagrid bulkActionButtons>` prop](./Datagrid.md#bulkactionbuttons).

### Usage
```jsx
import * as React from 'react';
import { Fragment } from 'react';
import { BulkDeleteButton, BulkExportButton } from 'react-admin';
const PostBulkActionButtons = () => (
<Fragment>
<BulkExportButton />
<BulkDeleteButton />
</Fragment>
);
export const PostList = () => (
<List>
<Datagrid bulkActionButtons={<PostBulkActionButtons />}>
...
</Datagrid>
</List>
);
```
### Props
| Prop | Required | Type | Default | Description |
| ------------ | -------- | --------------- | ------------------ | ----------------------------------- |
| `label` | Optional | `string` | 'ra.action.export' | label or translation message to use |
| `icon` | Optional | `ReactElement` | `<DownloadIcon>` | iconElement, e.g. `<CommentIcon />` |
| `exporter` | Optional | `Function` | - | Override the List exporter function |
| `meta` | Optional | `any` | undefined | Metadata passed to the dataProvider |
## `<BulkUpdateButton>`
Partially updates the selected rows. To be used inside [the `<Datagrid bulkActionButtons>` prop](./Datagrid.md#bulkactionbuttons).

### Usage
{% raw %}
```jsx
import * as React from 'react';
import { Fragment } from 'react';
import { BulkDeleteButton, BulkExportButton, BulkUpdateButton } from 'react-admin';
const PostBulkActionButtons = () => (
<Fragment>
<BulkExportButton />
<BulkUpdateButton data={{ published_at: new Date() }} />
<BulkDeleteButton />
</Fragment>
);
export const PostList = () => (
<List>
<Datagrid bulkActionButtons={<PostBulkActionButtons />}>
...
</Datagrid>
</List>
);
```
{% endraw %}
### Props
| Prop | Required | Type | Default | Description |
|-------------------|----------|----------------|--------------------|---------------------------------------------------------------------------------------------------------------------|
| `data` | Required | `object` | - | An object with the fields that need to be updated on the selected records |
| `confirmContent` | Optional | React node | - | Lets you customize the content of the confirm dialog. Only used in `'pessimistic'` or `'optimistic'` mutation modes |
| `confirmTitle` | Optional | `string` | - | Lets you customize the title of the confirm dialog. Only used in `'pessimistic'` or `'optimistic'` mutation modes |
| `icon` | Optional | `ReactElement` | `<ActionUpdate>` | An icon element |
| `label` | Optional | `string` | 'ra.action.update' | Label or translation message to use |
| `mutationMode` | Optional | `string` | `'undoable'` | Mutation mode (`'undoable'`, `'pessimistic'` or `'optimistic'`) |
| `mutationOptions` | Optional | `object` | null | Options for react-query `useMutation` hook |
| `successMessage` | Optional | `string` | 'ra.notification.updated'| Lets you customize the success notification message. |
**Tip:** If you choose the `'pessimistic'` or `'optimistic'` mutation mode, a confirm dialog will be displayed to the user before the mutation is executed.
### `successMessage`
On success, `<BulkUpdateButton>` displays a "XX elements updated" notification in English. `<BulkUpdateButton>` uses two successive translation keys to build the success message:
- `resources.{resource}.notifications.updated` as a first choice
- `ra.notification.updated` as a fallback
To customize the notification message, you can set custom translation for these keys in your i18nProvider.
**Tip**: If you choose to use a custom translation, be aware that react-admin uses the same translation message for the `<Edit>` success notification, so the message must support [pluralization](./TranslationTranslating.md#interpolation-pluralization-and-default-translation):
```jsx
const englishMessages = {
resources: {
posts: {
notifications: {
updated: 'Post updated |||| %{smart_count} postss updated',
// ...
},
},
},
};
```
Alternately, pass a `successMessage` prop:
{% raw %}
```jsx
<BulkUpdateButton
data={{ published_at: new Date() }}
successMessage="Posts deleted successfully"
/>
```
{% endraw %}
## `<BulkUpdateFormButton>`
This component, part of the [enterprise edition](https://react-admin-ee.marmelab.com/documentation/ra-form-layout)<img class="icon" src="./img/premium.svg" />, lets users edit multiple records at once. To be used inside [the `<Datagrid bulkActionButtons>` prop](./Datagrid.md#bulkactionbuttons).
<video controls autoplay playsinline muted loop>
<source src="./img/BulkUpdateButton-SimpleForm.webm" type="video/webm"/>
<source src="./img/BulkUpdateButton-SimpleForm.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>
The button opens a dialog containing the form passed as children. When the form is submitted, it will call the dataProvider's `updateMany` method with the ids of the selected records.
### Usage
`<BulkUpdateFormButton>` can be used inside `<Datagrid>`'s `bulkActionButtons`.
```tsx
import * as React from 'react';
import {
Admin,
BooleanField,
BooleanInput,
Datagrid,
DateField,
DateInput,
List,
Resource,
SimpleForm,
TextField,
} from 'react-admin';
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import { dataProvider } from './dataProvider';
import { i18nProvider } from './i18nProvider';
export const App = () => (
<Admin dataProvider={dataProvider} i18nProvider={i18nProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
const PostList = () => (
<List>
<Datagrid bulkActionButtons={<PostBulkUpdateButton />}>
<TextField source="id" />
<TextField source="title" />
<DateField source="published_at" />
<BooleanField source="is_public" />
</Datagrid>
</List>
);
```
**Tip:** You are not limited to using a `<SimpleForm>` as children. You can for instance use an `<InputSelectorForm>`, which allows to select the fields to update. Check out the [`<InputSelectorForm>`](#usage-with-inputselectorform) below for more information.
### Props
| Prop | Required | Type | Default | Description |
|-------------------|--------------|----------|-----------------|------------------------------------------------------------------------------------------------------------------------------------|
| `children` | Required (*) | Element | - | A form component to render inside the Dialog |
| `DialogProps` | - | Object | - | Additional props to pass to the [MUI Dialog](https://mui.com/material-ui/react-dialog/) |
| `mutationMode` | - | `string` | `'pessimistic'` | The mutation mode (`'undoable'`, `'pessimistic'` or `'optimistic'`) |
| `mutationOptions` | - | Object | - | Mutation options passed to [React Query](https://tanstack.com/query/v5/docs/react/reference/useMutation) when calling `updateMany` |
### `children`
`<BulkUpdateFormButton>` expects a form component as children, such as `<SimpleForm>` or `<InputSelectorForm>`.
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
### `DialogProps`
The `DialogProps` prop can be used to pass additional props to the [MUI Dialog](https://mui.com/material-ui/react-dialog/).
{% raw %}
```tsx
import { Slide } from '@mui/material';
import { TransitionProps } from '@mui/material/transitions';
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';
const Transition = React.forwardRef(function Transition(
props: TransitionProps & {
children: React.ReactElement<any, any>;
},
ref: React.Ref<unknown>
) {
return <Slide direction="left" ref={ref} {...props} />;
});
const PostBulkUpdateButtonWithTransition = () => (
<BulkUpdateFormButton DialogProps={{ TransitionComponent: Transition }}>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
{% endraw %}
### `mutationMode`
Use the `mutationMode` prop to specify the [mutation mode](https://marmelab.com/react-admin/Edit.html#mutationmode).
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton mutationMode="undoable">
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
### `mutationOptions` and `meta`
The `mutationOptions` prop can be used to pass options to the [react-query mutation](https://react-query.tanstack.com/reference/useMutation#options) used to call the dataProvider's `updateMany` method.
{% raw %}
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton mutationOptions={{ retry: false }}>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
{% endraw %}
You can also use this prop to pass a `meta` object, that will be passed to the dataProvider when calling `updateMany`.
{% raw %}
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton mutationOptions={{ meta: { foo: 'bar' } }}>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
{% endraw %}
### Usage with `<TabbedForm>` or other location based form layouts
`<BulkUpdateFormButton>` can be used with any form layout. However, for form layouts that are based on location by default, such as [`<TabbedForm>`](https://marmelab.com/react-admin/TabbedForm.html), you will need to disable the location syncing feature, as it may conflict with the Edit route declared by React Admin (`/<resource>/<id>`).
For instance, with `<TabbedForm>`, you can use the `syncWithLocation` prop to disable it:
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, TabbedForm } from 'react-admin';
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<TabbedForm syncWithLocation={false}>
<TabbedForm.Tab label="Publication">
<DateInput source="published_at" />
</TabbedForm.Tab>
<TabbedForm.Tab label="Visibility">
<BooleanInput source="is_public" />
</TabbedForm.Tab>
</TabbedForm>
</BulkUpdateFormButton>
);
```
### Usage With `<InputSelectorForm>`
`<BulkUpdateFormButton>` works best with `<InputSelectorForm>`, which component renders a form allowing to select the fields to update in a record.
<video controls autoplay playsinline muted loop>
<source src="./img/BulkUpdateButton-InputSelectorForm.webm" type="video/webm"/>
<source src="./img/BulkUpdateButton-InputSelectorForm.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>
`<InputSelectorForm>` expects a list of inputs passed in the `inputs` prop. Each input must have a `label` and an `element`.
```tsx
import {
BulkUpdateFormButton,
InputSelectorForm,
} from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput } from 'react-admin';
const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<InputSelectorForm
inputs={[
{
label: 'Published at',
element: <DateInput source="published_at" />,
},
{
label: 'Is public',
element: <BooleanInput source="is_public" />,
},
]}
/>
</BulkUpdateFormButton>
);
```
Use the `inputs` prop to specify the list of inputs from which the user can pick. Each input must have a `label` and an `element`.
```tsx
import { InputSelectorForm } from '@react-admin/ra-form-layout';
import * as React from 'react';
import {
BooleanInput,
DateInput,
SelectArrayInput,
TextInput,
} from 'react-admin';
const PostEdit = () => (
<InputSelectorForm
inputs={[
{
label: 'Title',
element: <TextInput source="title" />,
},
{
label: 'Body',
element: <TextInput source="body" multiline />,
},
{
label: 'Published at',
element: <DateInput source="published_at" />,
},
{
label: 'Is public',
element: <BooleanInput source="is_public" />,
},
{
label: 'Tags',
element: (
<SelectArrayInput
source="tags"
choices={[
{ id: 'react', name: 'React' },
{ id: 'vue', name: 'Vue' },
{ id: 'solid', name: 'Solid' },
{ id: 'programming', name: 'Programming' },
]}
/>
),
},
]}
/>
);
```
### Limitations
If you look under the hood, you will see that `<BulkUpdateFormButton>` provides a `<SaveContext>` to its children, which allows them to call `updateMany` with the ids of the selected records.
However since we are in the context of a list, there is no `<RecordContext>` available. Hence, the following inputs cannot work inside a `<BulkUpdateFormButton>`:
- `<ReferenceOneInput>`
- `<ReferenceManyInput>`
- `<ReferenceManyToManyInput>`
## `<Button>`
Base component for most react-admin buttons. Responsive (displays only the icon with a tooltip on mobile) and accessible.
```tsx
<Button label="Ban user" onClick={handleClick}>
<BanIcon />
</Button>
```
### Props
| Prop | Required | Type | Default | Description |
| ------------ | -------- | ------------------------------ | ------- | ---------------------------------------- |
| `alignIcon` | Optional | `'left' | 'right` | `'left'` | Icon position relative to the label |
| `children` | Optional | `ReactElement` | - | icon to use |
| `className` | Optional | `string` | - | Class name to customize the look and feel of the button element itself |
| `color` | Optional | `'default' | 'inherit'| 'primary' | 'secondary'` | `'primary'` | Label and icon color |
| `disabled` | Optional | `boolean` | `false` | If `true`, the button will be disabled |
| `size` | Optional | `'large' | 'medium' | 'small'` | `'small'` | Button size |
Other props are passed down to [the underlying Material UI `<Button>`](https://mui.com/material-ui/api/button/).
### `sx`: CSS API
| Rule name | Description |
|------------------------------|-------------------------------------------------------------------------------------------------|
| `& .RaButton-button` | Applied to the underlying `MuiButton` component |
| `& .RaButton-label` | Applied to the Button's label when `alignIcon` prop is 'left' |
| `& .RaButton-labelRightIcon` | Applied to the Button's label when `alignIcon` prop is 'left' |
| `& .RaButton-smallIcon` | Applied to the Button's `children` when `size` prop is `small` and `alignIcon` prop is 'right' |
| `& .RaButton-mediumIcon` | Applied to the Button's `children` when `size` prop is `medium` and `alignIcon` prop is 'right' |
| `& .RaButton-largeIcon` | Applied to the Button's `children` when `size` prop is `large` and `alignIcon` prop is 'right' |
To override the style of all instances of `<Button>` using the [application-wide style overrides](./AppTheme.md#theming-individual-components), use the `RaButton` key.
## `<CloneButton>`
The `<CloneButton>` can be added anywhere there is a `RecordContext` to redirect users to the record's resource create page. The create page form will be prefilled with the record values (except the `id`).
### Usage
`<CloneButton>` reads the current resource from `ResourceContext`, so in general it doesn't need any props:
```jsx
import { CloneButton, TopToolbar, List } from 'react-admin';
const PostList = () => (
<List>
<TextField source="title" />
<CloneButton />
</List>
);
```
`<CloneButton>` is based on react-admin's base `<Button>`, so it's responsive, accessible, and the label is translatable.
### Props
| Prop | Required | Type | Default | Description |
| ------------- | -------- | --------------- | ------------------ | -------------------------------------------- |
| `resource` | Optional | `string` | - | Target resource, e.g. 'posts' |
| `label` | Optional | `string` | 'ra.action.create' | label or translation message to use |
| `icon` | Optional | `ReactElement` | - | iconElement, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |
It also supports [all the other `<Button>` props](#button).
### `scrollToTop`
By default, `<CloneButton>` scrolls the page to the top after redirecting to the create view. You can disable it as follows:
```jsx
const CloneButtonWithoutScrollToTop = () => <CloneButton scrollToTop={false} />
```
### Access Control
If you want to control whether this button should be displayed based on users permissions, use the `<CloneButton>` exported by the `@react-admin/ra-rbac` Enterprise package.
```diff
-import { CloneButton } from 'react-admin';
+import { CloneButton } from '@react-admin/ra-rbac';
```
This component adds the following [RBAC](./AuthRBAC.md) controls:
- It will only render if the user has the `'clone'` permission on the current resource.
```js
{ action: "clone", resource: [current resource] }
```
Here is an example of how to use the `<CloneButton>` with RBAC:
```tsx
import { Edit, TopToolbar } from 'react-admin';
import { CloneButton } from '@react-admin/ra-rbac';
const PostEditActions = () => (
<TopToolbar>
<CloneButton />
</TopToolbar>
);
export const PostEdit = () => (
<Edit actions={<PostEditActions />}>
{/* ... */}
</Edit>
);
```
This component accepts additional props:
| Prop | Required | Type | Default | Description |
| -------------------- | -------- | ----------------- | ---------- | ---------------------------------------------------------------------- |
| `accessDenied` | Optional | ReactNode | null | The content to display when users don't have the `'clone'` permission |
| `action` | Optional | String | `"clone"` | The action to call `authProvider.canAccess` with |
| `authorizationError` | Optional | ReactNode | null | The content to display when an error occurs while checking permission |
## `<CreateButton>`
Opens the Create view of the current resource:

On mobile, it turns into a "Floating Action Button".

### Usage
`<CreateButton>` reads the current resource from `ResourceContext`, so in general it doesn't need any props:
```jsx
import { CreateButton, TopToolbar, List } from 'react-admin';
const ListActions = () => (
<TopToolbar>
<CreateButton />
</TopToolbar>
);
const CommentList = () => (
<List actions={<ListActions />}>
{/* ... */}
</List>
);
```
`<CreateButton>` is based on react-admin's base `<Button>`, so it's responsive, accessible, and the label is translatable.
### Props
| Prop | Required | Type | Default | Description |
| ------------- | -------- | --------------- | ------------------ | -------------------------------------------- |
| `resource` | Optional | `string` | - | Target resource, e.g. 'posts' |
| `label` | Optional | `string` | 'ra.action.create' | label or translation message to use |
| `icon` | Optional | `ReactElement` | - | iconElement, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |
It also supports [all the other `<Button>` props](#button).
**Tip**: If you want to link to the Create view manually, use the `/{resource}/create` location.
**Tip:** To allow users to create a record without leaving the current view, use the [`<CreateInDialogButton>`](./CreateInDialogButton.md) component.
### `scrollToTop`
By default, `<CreateButton>` scrolls the page to the top after redirecting. You can disable it as follows:
```jsx
const CreateButtonWithoutScrollToTop = () => <CreateButton scrollToTop={false} />
```
### `sx`: CSS API
| Rule name | Description |
|-----------------------------|--------------------------------------------------------------------|
| `&.RaCreateButton-floating` | Applied to the underlying `MuiFab` component used in small screens |
To override the style of all instances of `<CreateButton>` using the [application-wide style overrides](./AppTheme.md#theming-individual-components), use the `RaCreateButton` key.
### Access Control
If your `authProvider` implements [Access Control](./Permissions.md#access-control), `<CreateButton>` will only render if the user has the "create" access to the related resource.
`<CreateButton>` will call `authProvider.canAccess()` using the following parameters:
```txt
{ action: "create", resource: [current resource] }
```
## `<DeleteButton>`
Delete the current record.

### Usage
`<DeleteButton>` reads the current record from `RecordContext`, and the current resource from `ResourceContext`, so in general it doesn't need any props:
```jsx
import { DeleteButton } from 'react-admin';
const CommentShow = () => (
<>
{/* ... */}
<DeleteButton />
</>
);
```
When pressed, it will call `dataProvider.delete()` with the current record's `id`.
You can also call it with a record and a resource:
{% raw %}
```jsx
<DeleteButton record={{ id: 123, author: 'John Doe' }} resource="comments" />
```
{% endraw %}
### Props
| Prop | Required | Type | Default | Description |
|-------------------- |----------|--------------------------------- |-------------------|-------------------------------------------------------------------------|
| `className` | Optional | `string` | - | Class name to customize the look and feel of the button element itself |
| `label` | Optional | `string` | 'Delete' | label or translation message to use |
| `icon` | Optional | `ReactElement` | `<DeleteIcon>` | iconElement, e.g. `<CommentIcon />` |
| `mutationMode` | Optional | `string` | `'undoable'` | Mutation mode (`'undoable'`, `'pessimistic'` or `'optimistic'`) |
| `mutation Options` | Optional | | null | options for react-query `useMutation` hook |
| `record` | Optional | `Object` | - | Record to delete, e.g. `{ id: 12, foo: 'bar' }` |
| `redirect` | Optional | `string | false | Function` | 'list' | Custom redirection after success side effect |
| `resource` | Optional | `string` | - | Resource to delete, e.g. 'posts' |
| `sx` | Optional | `SxProps` | - | The custom styling for the button |
| `success Message` | Optional | `string` | 'Element deleted' | Lets you customize the success notification message. |
### `label`
By default, the label is `Delete` in English. In other languages, it's the translation of the `'ra.action.delete'` key.
To customize the `<DeleteButton>` label, you can either change the translation in your i18nProvider, or pass a `label` prop:
```jsx
<DeleteButton label="Delete this comment" />
```
Custom labels are automatically translated, so you can use a translation key, too:
```jsx
<DeleteButton label="resources.comments.actions.delete" />
```
### `icon`
Customize the icon of the button by passing an `icon` prop:
```jsx
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
<DeleteButton icon={<DeleteForeverIcon />} />
```
### `mutationMode`
`<DeleteButton>` has three modes, depending on the `mutationMode` prop:
- `'undoable'` (default): Clicking the button will update the UI optimistically and display a confirmation snackbar with an undo button. If the user clicks the undo button, the record will not be deleted and the UI will be rolled back. Otherwise, the record will be deleted after 5 seconds.
- `optimistic`: Clicking the button will update the UI optimistically and delete the record. If the deletion fails, the UI will be rolled back.
- `pessimistic`: Clicking the button will display a confirmation dialog. If the user confirms, the record will be deleted. If the user cancels, nothing will happen.
**Note**: When choosing the `pessimistic` mode, `<DeleteButton>` will actually render a `<DeleteWithConfirmButton>` component and accept additional props to customize the confirm dialog (see below).
### `mutationOptions`
`<DeleteButton>` calls the `useMutation` hook internally to delete the record. You can pass options to this hook using the `mutationOptions` prop.
{% raw %}
```jsx
<DeleteButton mutationOptions={{ onError: () => alert('Record not deleted, please retry') }} />
```
{% endraw %}
Check out the [useMutation documentation](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) for more information on the available options.
### `record`
By default, `<DeleteButton>` reads the current record from the `RecordContext`. If you want to delete a different record, you can pass it as a prop:
{% raw %}
```jsx
<DeleteButton record={{ id: 123, author: 'John Doe' }} />
```
{% endraw %}
### `redirect`
By default, `<DeleteButton>` redirects to the list page after a successful deletion. You can customize the redirection by passing a path as the `redirect` prop:
```jsx
<DeleteButton redirect="/comments" />
```
### `resource`
By default, `<DeleteButton>` reads the current resource from the `ResourceContext`. If you want to delete a record from a different resource, you can pass it as a prop:
{% raw %}
```jsx
<DeleteButton record={{ id: 123, author: 'John Doe' }} resource="comments" />
```
{% endraw %}
### `successMessage`

On success, `<DeleteButton>` displays a "Element deleted" notification in English. `<DeleteButton>` uses two successive translation keys to build the success message:
- `resources.{resource}.notifications.deleted` as a first choice
- `ra.notification.deleted` as a fallback
To customize the notification message, you can set custom translation for these keys in your i18nProvider.
**Tip**: If you choose to use a custom translation, be aware that react-admin uses the same translation message for the `<BulkDeleteButton>`, so the message must support [pluralization](./TranslationTranslating.md#interpolation-pluralization-and-default-translation):
```jsx
const englishMessages = {
resources: {
comments: {
notifications: {
deleted: 'Comment deleted |||| %{smart_count} comments deleted',
// ...
},
},
},
};
```
Alternately, pass a `successMessage` prop:
```jsx
<DeleteButton successMessage="Comment deleted successfully" />
```
### Access Control
If your `authProvider` implements [Access Control](./Permissions.md#access-control), `<DeleteButton>` will only render if the user has the "delete" access to the related resource.
`<DeleteButton>` will call `authProvider.canAccess()` using the following parameters:
```txt
{ action: "delete", resource: [current resource], record: [current record] }
```
## `<DeleteWithConfirmButton>`
Delete the current record after a confirm dialog has been accepted. To be used inside a `<Toolbar/>` component.
| Prop | Required | Type | Default | Description |
|------------------- |----------|--------------------------------------------------|-----------------------------|-------------------------------------------------------------------------|
| `className` | Optional | `string` | - | Class name to customize the look and feel of the button element itself |
| `label` | Optional | `string` | 'ra.action.delete' | label or translation message to use |
| `icon` | Optional | `ReactElement` | `<DeleteIcon>` | iconElement, e.g. `<CommentIcon />` |
| `confirmTitle` | Optional | `ReactNode` | 'ra.message.delete_title' | Title of the confirm dialog |
| `confirmContent` | Optional | `ReactNode` | 'ra.message.delete_content' | Message or React component to be used as the body of the confirm dialog |
| `confirmColor` | Optional | <code>'primary' | 'warning'</code> | 'primary' | The color of the confirm dialog's "Confirm" button |
| `redirect` | Optional | <code>string | false | Function</code> | 'list' | Custom redirection after success side effect |
| `translateOptions` | Optional | `{ id?: string, name?: string }` | {} | Custom id and name to be used in the confirm dialog's title |
| `mutationOptions` | Optional | | null | options for react-query `useMutation` hook |
| `successMessage` | Optional | `string` | 'ra.notification.deleted' | Lets you customize the success notification message. |
{% raw %}
```jsx
import * as React from 'react';
import { DeleteWithConfirmButton, Toolbar, Edit, SaveButton,useRecordContext } from 'react-admin';
const EditToolbar = () => {
const record = useRecordContext();
<Toolbar>
<SaveButton/>
<DeleteWithConfirmButton
confirmContent="You will not be able to recover this record. Are you sure?"
confirmColor="warning"
translateOptions={{ name: record.name }}
/>
</Toolbar>
};
const MyEdit = () => (
<Edit>
<SimpleForm toolbar={<EditToolbar />}>
...
</SimpleForm>
</Edit>
);
```
{% endraw %}
## `<EditButton>`
Opens the Edit view of the current record.

### Usage
`<EditButton>` reads the current record from `RecordContext`, and the current resource from `ResourceContext`, so in general it doesn't need any props:
```jsx
import { EditButton, TopToolbar } from 'react-admin';
const ShowActions = () => (
<TopToolbar>
<EditButton />
</TopToolbar>
);
const CommentShow = () => (
<Show actions={<ShowActions />}>
{/* ... */}
</Show>
);
```
`<EditButton>` is based on react-admin's base `<Button>`, so it's responsive, accessible, and the label is translatable.
### Props
| Prop | Required | Type | Default | Description |
| ------------- | -------- | --------------- | ---------------- | ------------------------------------------------ |
| `resource` | Optional | `string` | - | Resource to link to, e.g. 'posts' |
| `record` | Optional | `Object` | - | Record to link to, e.g. `{ id: 12, foo: 'bar' }` |
| `label` | Optional | `string` | 'ra.action.edit' | Label or translation message to use |
| `icon` | Optional | `ReactElement` | - | Icon element, e.g. `<CommentIcon />` |
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |
It also supports [all the other `<Button>` props](#button).
**Tip**: You can use it as `<Datagrid>` child, too. However, you should use the `<Datagrid rowClick="edit">` prop instead to avoid using one column for the Edit button.
**Tip**: If you want to link to the Edit view manually, use the `/{resource}/{record.id}` location.
**Tip:** To allow users to edit a record without leaving the current view, use the [`<EditInDialogButton>`](./EditInDialogButton.md) component.
### `scrollToTop`
By default, `<EditButton>` scrolls the page to the top after redirecting. You can disable it as follows:
```jsx
const EditButtonWithoutScrollToTop = () => <EditButton scrollToTop={false} />
```
### Access Control
If your `authProvider` implements [Access Control](./Permissions.md#access-control), `<EditButton>` will only render if the user has the "edit" access to the related resource.
`<EditButton>` will call `authProvider.canAccess()` using the following parameters: