# Customizing the Admin
## Preparing your App
```javascript
import React from 'react';
import { HydraAdmin, replaceResources } from '@api-platform/admin';
import parseHydraDocumentation from '@api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation';
import { greetingsNameInput } from './components/greetings/inputs.js';
import { greetingsNameField } from './components/greetings/fields.js';
import BookList from './components/books/list.js';
import BookCreate from './components/books/create.js';
import BookEdit from './components/books/edit.js';
import { booksDescriptionInput } from './components/books/inputs.js';
const entrypoint = process.env.REACT_APP_API_ENTRYPOINT;
const greetings = {
name: 'greetings',
fields: [
{
name: 'name',
input: greetingsNameInput,
field: greetingsNameField,
}
],
listFields: [
// list here all fields you want to be displayed in the List view
],
};
const books = {
name: 'books',
list: BookList,
create: BookCreate,
edit: BookEdit,
fields: [
{
name: 'description',
input: booksDescriptionInput,
}
]
};
const newResources = [
greetings,
books,
];
const myApiDocumentationParser = entrypoint => parseHydraDocumentation(entrypoint)
.then(({ api }) => {
replaceResources(api.resources, newResources);
return { api };
})
;
export default () => ;
```
All you have to do is to provide a collection of objects (the `newResources` variable).
The value of the `name` property must match the resource name you want to customize, or it will be ignored.
Other available properties will be explained further.
## Customizing Inputs
```javascript
import React from 'react';
import { TextInput } from 'react-admin';
const myInput = props => (
);
const greetings = {
name: 'greetings',
fields: [
{
name: 'name',
input: myInput,
},
],
};
export default [
greetings,
];
```
That's it! Our custom `TextInput` component will now be used in all forms to edit the `name` property of the `greeting` resource.
In this example, we are reusing an `Input` component provided by `react-admin`, but you can use any component you want as long as you respect [the signature expected by react-admin](https://marmelab.com/react-admin/Inputs.html).
## Customizing Fields
```javascript
import React from 'react';
import { UrlField } from 'react-admin';
const myField = props => (
);
const greetings = {
name: 'greetings',
fields: [
{
name: 'url',
field: myField,
},
],
};
export default [
greetings,
];
```
That's it! Our custom `myField` component will now be used to display the resource.
In this example, we are reusing a `Field` component provided by `react-admin`, but you can use any component you want as long as you respect [the signature expected by react-admin](https://marmelab.com/react-admin/Fields.html).
## "Free" Mode
If you want to fully customize the admin, here is how you can do it:
```javascript
import React from 'react';
const GreetingList = props =>
Yay! I can do what I want!
;
const GreetingCreate = props => Yay! I can do what I want!
;
const GreetingEdit = props => Yay! I can do what I want!
;
const greetings = {
name: 'greetings',
list: GreetingList,
create: GreetingCreate,
edit: GreetingEdit,
};
export default [
greetings,
];
```
## Reusing the Default Layout
Most of the time you want to keep the default layout and just customize what is inside, here is how to do it:
### List
```javascript
import React from 'react';
import { List, Datagrid } from 'react-admin';
const GreetingList = props => {
const getField = fieldName => {
const {options: {resource: {fields}}} = props;
return fields.find(resourceField => resourceField.name === fieldName) ||
null;
};
const displayField = fieldName => {
const {options: {api, fieldFactory, resource}} = props;
const field = getField(fieldName);
if (field === null) {
return;
}
return fieldFactory(field, {api, resource});
};
return (
{displayField('name')}
);
};
const greetings = {
name: 'greetings',
list: GreetingList,
};
export default [
greetings,
];
```
### Create
#### Customizing the Form Layout
```javascript
import React from 'react';
import { Create, SimpleForm } from 'react-admin';
import { getResourceField } from '@api-platform/admin/lib/docsUtils';
const GreetingCreate = props => {
const {options: {inputFactory, resource}} = props;
return (
{inputFactory(getResourceField(resource, 'name'))}
{inputFactory(getResourceField(resource, 'description'))}
);
};
const greetings = {
name: 'greetings',
create: GreetingCreate,
};
export default [
greetings,
];
```
This way, we have been reusing most of the default behavior, but we managed to had a custom grid. This could also be a way to customize the fields order, and many more things you could think of.
#### Dynamic Display
If you want to have a form with dynamic display, just use a connected component like this one:
```javascript
import React from 'react';
import { connect } from 'react-redux';
import { formValueSelector } from 'redux-form';
import { getResourceField } from '@api-platform/admin/lib/docsUtils';
import { Create, SimpleForm } from 'react-admin';
const GreetingCreateView = props => {
const {options: {inputFactory, resource}, formValueName} = props;
return (
{inputFactory(getResourceField(resource, 'name'))}
{formValueName && (
inputFactory(getResourceField(resource, 'description'))
)}
);
};
const mapStateToProps = state => ({
formValueName: formValueSelector('record-form')(state, 'name'),
});
const GreetingCreate = connect(mapStateToProps)(GreetingCreateView);
const greetings = {
name: 'greetings',
create: GreetingCreate,
};
export default [
greetings,
];
```
### Edit
```javascript
import React from 'react';
import { Edit, SimpleForm } from 'react-admin';
import { getResourceField } from '@api-platform/admin/lib/docsUtils';
const GreetingEdit = props => {
const {options: {inputFactory, resource}} = props;
return (
{inputFactory(getResourceField(resource, 'name'))}
{inputFactory(getResourceField(resource, 'description'))}
);
};
const greetings = {
name: 'greetings',
edit: GreetingEdit,
};
export default [
greetings,
];
```
In this example, we have been able to customize the template to add a custom grid, but you could do more, have a look at the `Create`part above to see more examples.