ra-form-layout
New form layouts for complex data entry tasks (accordion, wizard, etc.).
Test it live on the Enterprise Edition Storybook and in the e-commerce demo (Accordion Form, WizardForm).
Installation
npm install --save @react-admin/ra-form-layout
# or
yarn add @react-admin/ra-form-layout
Tip: ra-form-layout
is part of the React-Admin Enterprise Edition, and hosted in a private npm registry. You need to subscribe to one of the Enterprise Edition plans to access this package.
The package contains new translation messages (in English and French). You should add them to your i18nProvider
:
import { Admin } from 'react-admin';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import frenchMessages from 'ra-language-french';
import {
raFormLayoutLanguageEnglish,
raFormLayoutLanguageFrench,
} from '@react-admin/ra-form-layout';
const messages = {
en: { ...englishMessages, ...raFormLayoutLanguageEnglish },
fr: { ...frenchMessages, ...raFormLayoutLanguageFrench },
};
const i18nProvider = polyglotI18nProvider(locale => messages[locale], 'en');
const App = () => <Admin i18nProvider={is18nProvider}>{/* ... */}</Admin>;
import { Admin } from "react-admin";
import polyglotI18nProvider from "ra-i18n-polyglot";
import englishMessages from "ra-language-english";
import frenchMessages from "ra-language-french";
import { raFormLayoutLanguageEnglish, raFormLayoutLanguageFrench } from "@react-admin/ra-form-layout";
const messages = {
en: { ...englishMessages, ...raFormLayoutLanguageEnglish },
fr: { ...frenchMessages, ...raFormLayoutLanguageFrench },
};
const i18nProvider = polyglotI18nProvider((locale) => messages[locale], "en");
const App = () => <Admin i18nProvider={is18nProvider}>{/* ... */}</Admin>;
<AccordionForm>
Alternative to <SimpleForm>
, to be used as child of <Create>
or <Edit>
. Expects <AccordionFormPanel>
elements as children.
Test it live in the e-commerce demo.
By default, each child accordion element handles its expanded state independently.
import {
Edit,
EditProps,
TextField,
TextInput,
DateInput,
SelectInput,
ArrayInput,
SimpleFormIterator,
BooleanInput,
} from 'react-admin';
import { AccordionForm, AccordionFormPanel } from '@react-admin/ra-form-layout';
// don't forget the component="div" prop on the main component to disable the main Card
const CustomerEdit = (props: EditProps) => (
<Edit {...props} component="div">
<AccordionForm autoClose>
<AccordionFormPanel label="Identity">
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="dob" label="born" validate={required()} />
<SelectInput source="sex" choices={sexChoices} />
</AccordionFormPanel>
<AccordionFormPanel label="Occupations">
<ArrayInput source="occupations" label="">
<SimpleFormIterator>
<TextInput source="name" validate={required()} />
<DateInput source="from" validate={required()} />
<DateInput source="to" />
</SimpleFormIterator>
</ArrayInput>
</AccordionFormPanel>
<AccordionFormPanel label="Preferences">
<SelectInput
source="language"
choices={languageChoices}
defaultValue="en"
/>
<BooleanInput source="dark_theme" />
<BooleanInput source="accepts_emails_from_partners" />
</AccordionFormPanel>
</AccordionForm>
</Edit>
);
import {
Edit,
TextField,
TextInput,
DateInput,
SelectInput,
ArrayInput,
SimpleFormIterator,
BooleanInput,
} from "react-admin";
import { AccordionForm, AccordionFormPanel } from "@react-admin/ra-form-layout";
// don't forget the component="div" prop on the main component to disable the main Card
const CustomerEdit = (props) => (
<Edit {...props} component="div">
<AccordionForm autoClose>
<AccordionFormPanel label="Identity">
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="dob" label="born" validate={required()} />
<SelectInput source="sex" choices={sexChoices} />
</AccordionFormPanel>
<AccordionFormPanel label="Occupations">
<ArrayInput source="occupations" label="">
<SimpleFormIterator>
<TextInput source="name" validate={required()} />
<DateInput source="from" validate={required()} />
<DateInput source="to" />
</SimpleFormIterator>
</ArrayInput>
</AccordionFormPanel>
<AccordionFormPanel label="Preferences">
<SelectInput source="language" choices={languageChoices} defaultValue="en" />
<BooleanInput source="dark_theme" />
<BooleanInput source="accepts_emails_from_partners" />
</AccordionFormPanel>
</AccordionForm>
</Edit>
);
autoClose
When setting autoClose
in the <AccordionForm>
, only one accordion remains open at a time. The first accordion is open by default, and when a user opens another one, the current open accordion closes.
import { Edit, TextField, TextInput, DateInput, SelectInput, ArrayInput, SimpleFormIterator, BooleanInput } from 'react-admin';
import { AccordionForm, AccordionFormPanel } from '@react-admin/ra-form-layout';
// don't forget the component="div" prop on the main component to disable the main Card
const CustomerEdit = (props: EditProps) => (
<Edit {...props} component="div">
- <AccordionForm>
+ <AccordionForm autoClose>
<AccordionFormPanel label="Identity" defaultExpanded>
<TextField source="id" />
...
toolbar
You can customize the form Toolbar by passing a custom element in the toolbar
prop. The form expects the same type of element as <SimpleForm>
, see the <SimpleForm toolbar>
prop documentation in the react-admin docs.
<AccordionFormPanel>
Renders a material-ui <Accordion>
component. In the <AccordionDetails>
, renders each child inside a <FormInput>
(the same layout as in <SimpleForm>
).
Prop | Required | Type | Default | Description |
---|---|---|---|---|
label |
Required | string |
- | The main label used as the accordion summary. Appears in red when the accordion has errors |
children |
Required | ReactNode |
- | A list of <Input> elements |
secondary |
Optional | string |
- | The secondary label used as the accordion summary |
defaultExpanded |
Optional | boolean |
false |
Set to true to have the accordion expanded by default (except if autoClose = true on the parent) |
disabled |
Optional | boolean |
false |
If true, the accordion will be displayed in a disabled state. |
square |
Optional | boolean |
false |
If true, rounded corners are disabled. |
import {
Edit,
EditProps,
TextField,
TextInput,
DateInput,
SelectInput,
ArrayInput,
SimpleFormIterator,
BooleanInput,
} from 'react-admin';
import { AccordionForm, AccordionFormPanel } from '@react-admin/ra-form-layout';
const CustomerEdit = (props: EditProps) => (
<Edit {...props} component="div">
<AccordionForm>
<AccordionFormPanel label="Identity" defaultExpanded>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="dob" label="born" validate={required()} />
<SelectInput source="sex" choices={sexChoices} />
</AccordionFormPanel>
</AccordionForm>
</Edit>
);
import { Edit, TextField, TextInput, DateInput, SelectInput } from "react-admin";
import { AccordionForm, AccordionFormPanel } from "@react-admin/ra-form-layout";
const CustomerEdit = (props) => (
<Edit {...props} component="div">
<AccordionForm>
<AccordionFormPanel label="Identity" defaultExpanded>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="dob" label="born" validate={required()} />
<SelectInput source="sex" choices={sexChoices} />
</AccordionFormPanel>
</AccordionForm>
</Edit>
);
<AccordionSection>
Renders children (Inputs) inside a material-ui <Accordion>
element without a Card style. To be used as child of a <SimpleForm>
or a <TabbedForm>
element.
Prefer <AccordionSection>
to <AccordionForm>
to always display a list of important inputs, then offer accordions for secondary inputs.
Prop | Required | Type | Default | Description |
---|---|---|---|---|
Accordion |
Optional | Component |
- | The component to use as the accordion. |
AccordionDetails |
Optional | Component |
- | The component to use as the accordion details. |
AccordionSummary |
Optional | Component |
- | The component to use as the accordion summary. |
label |
Required | string |
- | The main label used as the accordion summary. |
children |
Required | ReactNode |
- | A list of <Input> elements |
fullWidth |
Optional | boolean |
false |
If true, the Accordion take sthe entire form width. |
className |
Optional | string |
- | A class name to style the underlying <Accordion> |
secondary |
Optional | string |
- | The secondary label used as the accordion summary |
defaultExpanded |
Optional | boolean |
false |
Set to true to have the accordion expanded by default |
disabled |
Optional | boolean |
false |
If true, the accordion will be displayed in a disabled state. |
square |
Optional | boolean |
false |
If true, rounded corners are disabled. |
import {
Edit,
EditProps,
TextField,
TextInput,
DateInput,
SelectInput,
ArrayInput,
SimpleForm,
SimpleFormIterator,
BooleanInput,
} from 'react-admin';
import { AccordionForm, AccordionFormPanel } from '@react-admin/ra-form-layout';
const CustomerEdit = (props: EditProps) => (
<Edit {...props} component="div">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="dob" label="born" validate={required()} />
<SelectInput source="sex" choices={sexChoices} />
<AccordionSection label="Occupations" fullWidth>
<ArrayInput source="occupations" label="">
<SimpleFormIterator>
<TextInput source="name" validate={required()} />
<DateInput source="from" validate={required()} />
<DateInput source="to" />
</SimpleFormIterator>
</ArrayInput>
</AccordionSection>
<AccordionSection label="Preferences" fullWidth>
<SelectInput
source="language"
choices={languageChoices}
defaultValue="en"
/>
<BooleanInput source="dark_theme" />
<BooleanInput source="accepts_emails_from_partners" />
</AccordionSection>
</SimpleForm>
</Edit>
);
import {
Edit,
TextField,
TextInput,
DateInput,
SelectInput,
ArrayInput,
SimpleForm,
SimpleFormIterator,
BooleanInput,
} from "react-admin";
const CustomerEdit = (props) => (
<Edit {...props} component="div">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="dob" label="born" validate={required()} />
<SelectInput source="sex" choices={sexChoices} />
<AccordionSection label="Occupations" fullWidth>
<ArrayInput source="occupations" label="">
<SimpleFormIterator>
<TextInput source="name" validate={required()} />
<DateInput source="from" validate={required()} />
<DateInput source="to" />
</SimpleFormIterator>
</ArrayInput>
</AccordionSection>
<AccordionSection label="Preferences" fullWidth>
<SelectInput source="language" choices={languageChoices} defaultValue="en" />
<BooleanInput source="dark_theme" />
<BooleanInput source="accepts_emails_from_partners" />
</AccordionSection>
</SimpleForm>
</Edit>
);
<WizardForm>
Alternative to <SimpleForm>
that splits a form into a step-by-step interface, to facilitate the entry in long forms.
Test it live in the e-commerce demo.
Use <SimpleForm>
as the child of <Create>
. It expects <WizardFormStep>
elements as children.
import React from 'react';
import { Create, CreateProps, TextInput, required } from 'react-admin';
import { WizardForm, WizardFormStep } from '@react-admin/ra-form-layout';
const PostCreate = (props: CreateProps) => (
<Create {...props}>
<WizardForm>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
import React from "react";
import { Create, TextInput, required } from "react-admin";
import { WizardForm, WizardFormStep } from "@react-admin/ra-form-layout";
const PostCreate = (props) => (
<Create {...props}>
<WizardForm>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
Note: You can also use the <WizardForm>
as child of <Edit>
but it's considered as a bad practice to provide a wizard form for existing resources.
Tip: The label
prop of the <WizardFormStep>
component accepts a translation key:
import React from 'react';
import { Create, CreateProps, TextInput, required } from 'react-admin';
import { WizardForm, WizardFormStep } from '@react-admin/ra-form-layout';
const PostCreate = (props: CreateProps) => (
<Create {...props}>
<WizardForm>
<WizardFormStep label="myapp.posts.steps.general">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="myapp.posts.steps.description">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="myapp.posts.steps.misc">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
import React from "react";
import { Create, TextInput, required } from "react-admin";
import { WizardForm, WizardFormStep } from "@react-admin/ra-form-layout";
const PostCreate = (props) => (
<Create {...props}>
<WizardForm>
<WizardFormStep label="myapp.posts.steps.general">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="myapp.posts.steps.description">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="myapp.posts.steps.misc">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
toolbar
You can customize the form toolbar by passing a custom component in the toolbar
prop.
import React from 'react';
import { Create, CreateProps, TextInput, required } from 'react-admin';
import {
WizardForm,
WizardFormStep,
WizardToolbarProps,
} from '@react-admin/ra-form-layout';
const MyToolbar = ({
hasPreviousStep,
hasNextStep,
onPreviousClick,
onNextClick,
handleSubmit,
handleSubmitWithRedirect,
invalid,
redirect,
saving,
submitOnEnter,
}: WizardToolbarProps) => {
const save = handleSubmitWithRedirect || handleSubmit;
return (
<ul>
{hasPreviousStep ? (
<li>
<Button onClick={onPreviousClick}>PREVIOUS</Button>
</li>
) : null}
{hasNextStep ? (
<li>
<Button disabled={invalid} onClick={onNextClick}>
NEXT
</Button>
</li>
) : (
<li>
<Button disabled={invalid} onClick={save}>
SAVE
</Button>
</li>
)}
</ul>
);
};
const PostCreate = (props: CreateProps) => (
<Create {...props}>
<WizardForm toolbar={MyToolbar}>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
import React from "react";
import { Create, TextInput, required } from "react-admin";
import { WizardForm, WizardFormStep } from "@react-admin/ra-form-layout";
const MyToolbar = ({
hasPreviousStep,
hasNextStep,
onPreviousClick,
onNextClick,
handleSubmit,
handleSubmitWithRedirect,
invalid,
redirect,
saving,
submitOnEnter,
}) => {
const save = handleSubmitWithRedirect || handleSubmit;
return (
<ul>
{hasPreviousStep ? (
<li>
<Button onClick={onPreviousClick}>PREVIOUS</Button>
</li>
) : null}
{hasNextStep ? (
<li>
<Button disabled={invalid} onClick={onNextClick}>
NEXT
</Button>
</li>
) : (
<li>
<Button disabled={invalid} onClick={save}>
SAVE
</Button>
</li>
)}
</ul>
);
};
const PostCreate = (props) => (
<Create {...props}>
<WizardForm toolbar={MyToolbar}>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
progress
You can also customize the progress stepper by passing a custom component in the progress
prop.
import React from 'react';
import { Create, CreateProps, TextInput, required } from 'react-admin';
import {
WizardForm,
WizardFormStep,
WizardFormProgressProps,
} from '@react-admin/ra-form-layout';
const MyProgress = ({
currentStep,
onStepClick,
steps,
}: WizardFormProgressProps) => (
<ul>
{steps.map((step, index) => {
const label = React.cloneElement(step, { intent: 'label' });
return (
<li key={`step_${index}`}>
{!onStepClick ? (
<span
className={
currentStep === index ? 'active' : undefined
}
>
{label}
</span>
) : (
<button onClick={() => onStepClick(index)}>
{label}
</button>
)}
</li>
);
})}
</ul>
);
const PostCreate = (props: CreateProps) => (
<Create {...props}>
<WizardForm progress={MyProgress}>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
import React from "react";
import { Create, TextInput, required } from "react-admin";
import { WizardForm, WizardFormStep } from "@react-admin/ra-form-layout";
const MyProgress = ({ currentStep, onStepClick, steps }) => (
<ul>
{steps.map((step, index) => {
const label = React.cloneElement(step, { intent: "label" });
return (
<li key={`step_${index}`}>
{!onStepClick ? (
<span className={currentStep === index ? "active" : undefined}>{label}</span>
) : (
<button onClick={() => onStepClick(index)}>{label}</button>
)}
</li>
);
})}
</ul>
);
const PostCreate = (props) => (
<Create {...props}>
<WizardForm progress={MyProgress}>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
</WizardForm>
</Create>
);
Any additional props will be passed to the <Progress>
component.
Adding a Summary Final Step
In order to add a final step with a summary of the form values before submit, you can leverage react-final-form
<FormSpy>
component:
const PostCreate = (props: CreateProps) => (
<Create {...props}>
<WizardForm>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
<WizardFormStep label="">
<FormSpy subscription={{ values: true }}>
{formState => (
<>
<Typography>{formState.values.title}</Typography>
<Typography>
{formState.values.description}
</Typography>
<Typography>
{formState.values.fullDescription}
</Typography>
</>
)}
</FormSpy>
</WizardFormStep>
</WizardForm>
</Create>
);
const PostCreate = (props) => (
<Create {...props}>
<WizardForm>
<WizardFormStep label="First step">
<TextInput source="title" validate={required()} />
</WizardFormStep>
<WizardFormStep label="Second step">
<TextInput source="description" />
</WizardFormStep>
<WizardFormStep label="Third step">
<TextInput source="fullDescription" validate={required()} />
</WizardFormStep>
<WizardFormStep label="">
<FormSpy subscription={{ values: true }}>
{(formState) => (
<>
<Typography>{formState.values.title}</Typography>
<Typography>{formState.values.description}</Typography>
<Typography>{formState.values.fullDescription}</Typography>
</>
)}
</FormSpy>
</WizardFormStep>
</WizardForm>
</Create>
);
<CreateDialog>
, <EditDialog>
& <ShowDialog>
Sometimes it makes sense to edit or create a resource without leaving the context of the list page.
For those cases, you can use the <CreateDialog>
and <EditDialog>
components.
They accept a single child which is the form, either a <SimpleForm>
, a <TabbedForm>
or a custom one, just like the <Create>
and <Edit>
components.
import React from 'react';
import {
List,
Datagrid,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
DateInput,
DateField,
required,
} from 'react-admin';
import { EditDialog, CreateDialog, ShowDialog } from '@react-admin/ra-form-layout';
const CustomerList = props => (
<>
<List {...props}>
<Datagrid>...</Datagrid>
</List>
<EditDialog {...props}>
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput
source="date_of_birth"
label="born"
validate={required()}
/>
</SimpleForm>
</EditDialog>
<CreateDialog {...props}>
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput
source="date_of_birth"
label="born"
validate={required()}
/>
</SimpleForm>
</CreateDialog>
<ShowDialog {...props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
<DateField
source="date_of_birth"
label="born"
/>
</SimpleShowLayout>
</ShowDialog>
</>
);
import React from "react";
import {
List,
Datagrid,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
DateInput,
DateField,
required,
} from "react-admin";
import { EditDialog, CreateDialog, ShowDialog } from "@react-admin/ra-form-layout";
const CustomerList = (props) => (
<>
<List {...props}>
<Datagrid>...</Datagrid>
</List>
<EditDialog {...props}>
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="date_of_birth" label="born" validate={required()} />
</SimpleForm>
</EditDialog>
<CreateDialog {...props}>
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="date_of_birth" label="born" validate={required()} />
</SimpleForm>
</CreateDialog>
<ShowDialog {...props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
<DateField source="date_of_birth" label="born" />
</SimpleShowLayout>
</ShowDialog>
</>
);
Unlike the <Create>
and <Edit>
components, their title will be displayed in the <Dialog>
, not in the <AppBar>
.
import React from 'react';
import {
List,
Datagrid,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
DateInput,
DateField,
required,
} from 'react-admin';
import { EditDialog, CreateDialog, ShowDialog } from '@react-admin/ra-form-layout';
const CustomerEditTitle = ({ record }) =>
record ? (
<span>
{record.last_name} {record.first_name}
</span>
) : null;
const CustomerList = props => (
<>
<List {...props}>
<Datagrid>...</Datagrid>
</List>
<EditDialog {...props} title={<CustomerEditTitle />}>
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput
source="date_of_birth"
label="born"
validate={required()}
/>
</SimpleForm>
</EditDialog>
<CreateDialog {...props} title="Create a new customer">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput
source="date_of_birth"
label="born"
validate={required()}
/>
</SimpleForm>
</CreateDialog>
<ShowDialog {...props} title="Show customer">
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
<DateField
source="date_of_birth"
label="born"
/>
</SimpleShowLayout>
</ShowDialog>
</>
);
import React from "react";
import {
List,
Datagrid,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
DateInput,
DateField,
required,
} from "react-admin";
import { EditDialog, CreateDialog, ShowDialog } from "@react-admin/ra-form-layout";
const CustomerEditTitle = ({ record }) =>
record ? (
<span>
{record.last_name} {record.first_name}
</span>
) : null;
const CustomerList = (props) => (
<>
<List {...props}>
<Datagrid>...</Datagrid>
</List>
<EditDialog {...props} title={<CustomerEditTitle />}>
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="date_of_birth" label="born" validate={required()} />
</SimpleForm>
</EditDialog>
<CreateDialog {...props} title="Create a new customer">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="date_of_birth" label="born" validate={required()} />
</SimpleForm>
</CreateDialog>
<ShowDialog {...props} title="Show customer">
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
<DateField source="date_of_birth" label="born" />
</SimpleShowLayout>
</ShowDialog>
</>
);
Besides, you can also pass the props accepted by the material-ui <Dialog>
like fullWidth
or maxWidth
.
import React from 'react';
import {
List,
Datagrid,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
DateInput,
DateField,
required,
} from 'react-admin';
import { EditDialog, CreateDialog, ShowDialog } from '@react-admin/ra-form-layout';
const CustomerList = props => (
<>
<List {...props}>
<Datagrid>...</Datagrid>
</List>
<EditDialog {...props} fullWidth maxWidth="md">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput
source="date_of_birth"
label="born"
validate={required()}
/>
</SimpleForm>
</EditDialog>
<CreateDialog {...props} fullWidth maxWidth="md">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput
source="date_of_birth"
label="born"
validate={required()}
/>
</SimpleForm>
</CreateDialog>
<ShowDialog {...props} fullWidth maxWidth="md">
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
<DateField
source="date_of_birth"
label="born"
/>
</SimpleShowLayout>
</ShowDialog>
</>
);
import React from "react";
import {
List,
Datagrid,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
DateInput,
DateField,
required,
} from "react-admin";
import { EditDialog, CreateDialog, ShowDialog } from "@react-admin/ra-form-layout";
const CustomerList = (props) => (
<>
<List {...props}>
<Datagrid>...</Datagrid>
</List>
<EditDialog {...props} fullWidth maxWidth="md">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="date_of_birth" label="born" validate={required()} />
</SimpleForm>
</EditDialog>
<CreateDialog {...props} fullWidth maxWidth="md">
<SimpleForm>
<TextField source="id" />
<TextInput source="first_name" validate={required()} />
<TextInput source="last_name" validate={required()} />
<DateInput source="date_of_birth" label="born" validate={required()} />
</SimpleForm>
</CreateDialog>
<ShowDialog {...props} fullWidth maxWidth="md">
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
<DateField source="date_of_birth" label="born" />
</SimpleShowLayout>
</ShowDialog>
</>
);
CHANGELOG
v1.9.3
2022-05-30
- (fix) Fix
<EditDialog>
and<ShowDialog>
rendering their content whilerecord
is still undefined
v1.9.2
2022-05-16
- (fix) Fix
<EditDialog>
regression introduced in v1.9.1
v1.9.1
2022-05-16
- (fix) Fix
<EditDialog>
scrolls to top on submit and on cancel
v1.9.0
2022-01-05
- (feat) Add
<ShowDialog>
component
v1.8.1
2021-12-17
- (fix) Fix sanitize mutationMode out of WizardFormView
- (fix) Fix change justify for justifyContent prop
v1.8.0
2021-11-12
- (feat) Add ability to pass custom
<Stepper>
props to<WizardProgress>
v1.7.0
2021-08-03
- (feat) Add translation key support for the
label
prop of the<WizardFormStep>
v1.6.2
2021-07-06
- (doc) Add an example of summary step for the
<WizardForm>
v1.6.1
2021-06-29
- (fix) Update peer dependencies ranges (support react 17)
v1.6.0
2021-05-17
- (chore) Update
AccordionForm
to useFormGroupContext
for error tracking. - (feat) Ensure
AccordionFormPanel
,AccordionFormToolbar
andFormDialogTitle
styles are overridable through Material UI theme by providing it a key (RaAccordionFormPanel
,RaAccordionFormToolbar
andRaFormDialogTitle
).
v1.5.5
2021-04-29
- (fix) Allow additional properties on
AccordionSection
component
v1.5.4
2021-01-29
- (fix) Fix wizard form does not handle submit on enter correctly
v1.5.3
2021-01-18
- (fix) Fix dialog forms
v1.5.2
2020-11-04
- (fix) Fix dialog forms prop interfaces
v1.5.1
2020-11-03
- (fix) Fix providing sub-components (
Accordion
,<AccordionSummary>
and<AccordionDetails>
) should not be required.
v1.5.0
2020-11-02
- (feat) Allow customizing the accordion sub-components (
Accordion
,<AccordionSummary>
and<AccordionDetails>
) by providing your own.
v1.4.0
2020-10-26
- (feat) Allow customizing the accordion sub-components (
Accordion
,<AccordionSummary>
and<AccordionDetails>
) - (feat) Add types for the
<AccordionSection>
v1.3.0
2020-10-05
- (deps) Upgrade react-admin to v3.9.0
v1.2.0
2020-10-01
- (feat) Dialog Form (CreateDialog & EditDialog)
v1.1.0
2020-09-28
- (feat) Wizard Form
v1.0.1
2020-09-22
- (fix) Fix Storybook error on
history.replace
v1.0.0
2020-09-22
- First release