Skip to content

Commit 950d37f

Browse files
committed
docs: add documentation for custom field components with defaultProps
1 parent 4db8de3 commit 950d37f

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

docs/CustomFields.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# Custom Fields
2+
3+
This document explains how to create custom field components in react-admin that integrate seamlessly with the rest of the framework.
4+
5+
## Basic Structure
6+
7+
A custom field component should:
8+
9+
1. Extend the `FieldProps` interface
10+
2. Use the `useFieldValue` hook to get the field value
11+
3. Handle empty values appropriately
12+
4. Support translation
13+
5. Support the common field props (label, source, etc.)
14+
15+
Here's a basic example:
16+
17+
```tsx
18+
import * as React from 'react';
19+
import { Typography } from '@mui/material';
20+
import { useFieldValue, useTranslate, FieldProps } from 'react-admin';
21+
import { sanitizeFieldRestProps } from './sanitizeFieldRestProps';
22+
23+
export const CustomField = <RecordType extends Record<string, any> = Record<string, any>>(
24+
props: CustomFieldProps<RecordType>
25+
) => {
26+
const { className, emptyText, ...rest } = props;
27+
const value = useFieldValue(props);
28+
const translate = useTranslate();
29+
30+
if (value == null) {
31+
return emptyText ? (
32+
<Typography
33+
component="span"
34+
variant="body2"
35+
className={className}
36+
{...sanitizeFieldRestProps(rest)}
37+
>
38+
{translate(emptyText, { _: emptyText })}
39+
</Typography>
40+
) : null;
41+
}
42+
43+
return (
44+
<Typography
45+
component="span"
46+
variant="body2"
47+
className={className}
48+
{...sanitizeFieldRestProps(rest)}
49+
>
50+
{value}
51+
</Typography>
52+
);
53+
};
54+
55+
export interface CustomFieldProps<
56+
RecordType extends Record<string, any> = Record<string, any>
57+
> extends FieldProps<RecordType> {
58+
// Add any custom props here
59+
}
60+
```
61+
62+
## Using defaultProps for Labels
63+
64+
When creating a custom field component, it's recommended to use `defaultProps` to set default values for the `label` prop. This ensures consistent behavior across your application and makes the component more reusable.
65+
66+
Here's how to implement it:
67+
68+
```tsx
69+
import * as React from 'react';
70+
import { Typography } from '@mui/material';
71+
import { useFieldValue, useTranslate, FieldProps } from 'react-admin';
72+
import { sanitizeFieldRestProps } from './sanitizeFieldRestProps';
73+
74+
export const CustomField = <RecordType extends Record<string, any> = Record<string, any>>(
75+
props: CustomFieldProps<RecordType>
76+
) => {
77+
// ... component implementation
78+
};
79+
80+
CustomField.defaultProps = {
81+
label: 'Custom Field', // Default label
82+
addLabel: true, // Show label by default
83+
};
84+
85+
export interface CustomFieldProps<
86+
RecordType extends Record<string, any> = Record<string, any>
87+
> extends FieldProps<RecordType> {
88+
// Add any custom props here
89+
}
90+
```
91+
92+
The benefits of using `defaultProps` for labels include:
93+
94+
1. **Consistency**: All instances of your field will have a default label if none is provided
95+
2. **Type Safety**: TypeScript will know about the default values
96+
3. **Documentation**: It makes it clear what the default behavior is
97+
4. **Maintainability**: You can change the default value in one place
98+
99+
## Best Practices
100+
101+
1. **Always extend FieldProps**: This ensures your component supports all standard field props like `source`, `label`, `emptyText`, etc.
102+
103+
2. **Use defaultProps for common values**: Set sensible defaults for `label` and other commonly used props.
104+
105+
3. **Handle empty values**: Always check for null/undefined values and use the `emptyText` prop appropriately.
106+
107+
4. **Support translation**: Use the `useTranslate` hook for all user-facing strings, including the default label.
108+
109+
5. **Use sanitizeFieldRestProps**: This utility function removes field-specific props before passing them to the underlying component.
110+
111+
6. **Type your props properly**: Use generics to ensure type safety with your record type.
112+
113+
## Example with All Best Practices
114+
115+
```tsx
116+
import * as React from 'react';
117+
import { Typography } from '@mui/material';
118+
import { useFieldValue, useTranslate, FieldProps } from 'react-admin';
119+
import { sanitizeFieldRestProps } from './sanitizeFieldRestProps';
120+
121+
export const CustomField = <RecordType extends Record<string, any> = Record<string, any>>(
122+
props: CustomFieldProps<RecordType>
123+
) => {
124+
const { className, emptyText, ...rest } = props;
125+
const value = useFieldValue(props);
126+
const translate = useTranslate();
127+
128+
if (value == null) {
129+
return emptyText ? (
130+
<Typography
131+
component="span"
132+
variant="body2"
133+
className={className}
134+
{...sanitizeFieldRestProps(rest)}
135+
>
136+
{translate(emptyText, { _: emptyText })}
137+
</Typography>
138+
) : null;
139+
}
140+
141+
return (
142+
<Typography
143+
component="span"
144+
variant="body2"
145+
className={className}
146+
{...sanitizeFieldRestProps(rest)}
147+
>
148+
{translate(value.toString())}
149+
</Typography>
150+
);
151+
};
152+
153+
CustomField.defaultProps = {
154+
label: 'custom.field', // Translation key for default label
155+
addLabel: true,
156+
emptyText: 'custom.field.empty', // Translation key for empty state
157+
};
158+
159+
export interface CustomFieldProps<
160+
RecordType extends Record<string, any> = Record<string, any>
161+
> extends FieldProps<RecordType> {
162+
// Add any custom props here
163+
}
164+
```
165+
166+
## Usage
167+
168+
```tsx
169+
// Basic usage with default label
170+
<CustomField source="name" />
171+
172+
// Override default label
173+
<CustomField source="name" label="Custom Name" />
174+
175+
// Disable label
176+
<CustomField source="name" label={false} />
177+
178+
// Custom empty text
179+
<CustomField source="name" emptyText="No name provided" />
180+
```
181+
182+
Remember to add translations for your default labels and empty text messages in your translation files.

0 commit comments

Comments
 (0)