Skip to content

Commit a6f13f7

Browse files
authored
fix(ui): properly extracts label from field in FieldLabel component (#8190)
Although the `<FieldLabel />` component receives a `field` prop, it does not use this prop to extract the `label` from the field. This is currently only an issue when rendering this component directly, such as within `admin.components.Label`. The label simply won't appear unless explicitly provided, despite it being passed as `field.label`. This is not an issue when rendering field components themselves, because they properly thread this value through as a top-level prop. Here's an example of the issue: ```tsx import type { TextFieldLabelServerComponent } from 'payload' import { FieldLabel } from '@payloadcms/ui' import React from 'react' export const MyCustomLabelComponent: TextFieldLabelServerComponent = ({ clientField }) => { return ( <FieldLabel field={clientField} label={clientField.label} // this should not be needed! /> ) } ``` Here is the end result: ```tsx import type { TextFieldLabelServerComponent } from 'payload' import { FieldLabel } from '@payloadcms/ui' import React from 'react' export const MyCustomLabelComponent: TextFieldLabelServerComponent = ({ clientField }) => { return <FieldLabel field={clientField} /> } ```
1 parent 532e4b5 commit a6f13f7

File tree

24 files changed

+39
-96
lines changed

24 files changed

+39
-96
lines changed

packages/payload/src/admin/forms/Label.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ServerProps, StaticLabel } from '../../config/types.js'
2-
import type { ClientField, Field } from '../../fields/config/types.js'
2+
import type { Field } from '../../fields/config/types.js'
33
import type { MappedComponent } from '../types.js'
44
import type { ClientFieldWithOptionalType } from './Field.js'
55

@@ -27,7 +27,7 @@ export type FieldLabelServerProps<
2727
} & GenericLabelProps &
2828
Partial<ServerProps>
2929

30-
export type SanitizedLabelProps<TFieldClient extends ClientField> = Omit<
30+
export type SanitizedLabelProps<TFieldClient extends ClientFieldWithOptionalType> = Omit<
3131
FieldLabelClientProps<TFieldClient>,
3232
'label' | 'required'
3333
>

packages/richtext-lexical/src/field/Field.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ const RichTextComponent: React.FC<
4141
style,
4242
width,
4343
} = {},
44-
label,
4544
required,
4645
},
4746
field,
@@ -101,13 +100,7 @@ const RichTextComponent: React.FC<
101100
{...(errorProps || {})}
102101
alignCaret="left"
103102
/>
104-
<FieldLabel
105-
field={field}
106-
Label={Label}
107-
label={label}
108-
required={required}
109-
{...(labelProps || {})}
110-
/>
103+
<FieldLabel field={field} Label={Label} {...(labelProps || {})} />
111104
<div className={`${baseClass}__wrap`}>
112105
<ErrorBoundary fallbackRender={fallbackRender} onReset={() => {}}>
113106
<LexicalProvider

packages/richtext-slate/src/field/RichText.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ const RichTextField: React.FC<LoadedSlateFieldProps> = (props) => {
6666
style,
6767
width,
6868
} = {},
69-
label,
7069
required,
7170
},
7271
labelProps,
@@ -321,13 +320,7 @@ const RichTextField: React.FC<LoadedSlateFieldProps> = (props) => {
321320
width,
322321
}}
323322
>
324-
<FieldLabel
325-
Label={Label}
326-
label={label}
327-
required={required}
328-
{...(labelProps || {})}
329-
field={field}
330-
/>
323+
<FieldLabel Label={Label} {...(labelProps || {})} field={field} />
331324
<div className={`${baseClass}__wrap`}>
332325
<FieldError CustomError={Error} field={field} path={path} {...(errorProps || {})} />
333326
<Slate

packages/ui/src/elements/TableColumns/buildColumnState.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,7 @@ export const buildColumnState = (args: Args): Column[] => {
101101
? field.admin.components.Label
102102
: undefined
103103

104-
const Label = (
105-
<FieldLabel
106-
field={field}
107-
Label={CustomLabelToRender}
108-
label={'label' in field ? (field.label as StaticLabel) : undefined}
109-
unstyled
110-
/>
111-
)
104+
const Label = <FieldLabel field={field} Label={CustomLabelToRender} unstyled />
112105

113106
const fieldAffectsDataSubFields =
114107
field &&

packages/ui/src/fields/Array/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
239239
as="span"
240240
field={field}
241241
Label={field?.admin?.components?.Label}
242-
label={label}
243-
required={required}
244242
unstyled
245243
{...(labelProps || {})}
246244
/>

packages/ui/src/fields/Blocks/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,6 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => {
231231
as="span"
232232
field={field}
233233
Label={field?.admin?.components?.Description}
234-
label={label}
235-
required={required}
236234
unstyled
237235
{...(labelProps || {})}
238236
/>

packages/ui/src/fields/Code/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,7 @@ const CodeFieldComponent: CodeFieldClientComponent = (props) => {
8383
width,
8484
}}
8585
>
86-
<FieldLabel
87-
field={field}
88-
Label={field?.admin?.components?.Label}
89-
label={label}
90-
required={required}
91-
{...(labelProps || {})}
92-
/>
86+
<FieldLabel field={field} Label={field?.admin?.components?.Label} {...(labelProps || {})} />
9387
<div className={`${fieldBaseClass}__wrap`}>
9488
<FieldError
9589
CustomError={field?.admin?.components?.Error}

packages/ui/src/fields/DateTime/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,7 @@ const DateTimeFieldComponent: DateFieldClientComponent = (props) => {
8181
width,
8282
}}
8383
>
84-
<FieldLabel
85-
field={field}
86-
Label={field?.admin?.components?.Label}
87-
label={label}
88-
required={required}
89-
{...(labelProps || {})}
90-
/>
84+
<FieldLabel field={field} Label={field?.admin?.components?.Label} {...(labelProps || {})} />
9185
<div className={`${fieldBaseClass}__wrap`} id={`field-${path.replace(/\./g, '__')}`}>
9286
<FieldError
9387
CustomError={field?.admin?.components?.Error}

packages/ui/src/fields/Email/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,7 @@ const EmailFieldComponent: EmailFieldClientComponent = (props) => {
7777
width,
7878
}}
7979
>
80-
<FieldLabel
81-
field={field}
82-
Label={field?.admin?.components?.Label}
83-
label={label}
84-
required={required}
85-
{...(labelProps || {})}
86-
/>
80+
<FieldLabel field={field} Label={field?.admin?.components?.Label} {...(labelProps || {})} />
8781
<div className={`${fieldBaseClass}__wrap`}>
8882
<FieldError
8983
CustomError={field?.admin?.components?.Error}

packages/ui/src/fields/FieldLabel/index.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import type { FieldLabelClientComponent, GenericLabelProps } from 'payload'
3+
import type { FieldLabelClientComponent, GenericLabelProps, StaticLabel } from 'payload'
44

55
import { getTranslation } from '@payloadcms/translations'
66
import React from 'react'
@@ -44,9 +44,25 @@ const DefaultFieldLabel: React.FC<GenericLabelProps> = (props) => {
4444
export const FieldLabel: FieldLabelClientComponent = (props) => {
4545
const { Label, ...rest } = props
4646

47+
// Don't get `Label` from `field.admin.components.Label` here because
48+
// this will cause an infinite loop when threading field through custom usages of `FieldLabel`
4749
if (Label) {
4850
return <RenderComponent clientProps={rest} mappedComponent={Label} />
4951
}
5052

51-
return <DefaultFieldLabel {...rest} />
53+
return (
54+
<DefaultFieldLabel
55+
{...rest}
56+
label={
57+
typeof props?.label !== 'undefined'
58+
? props.label
59+
: props?.field && 'label' in props.field && (props.field.label as StaticLabel) // type assertion needed for `row` fields
60+
}
61+
required={
62+
typeof props.required !== 'undefined'
63+
? props.required
64+
: props?.field && 'required' in props.field && (props.field?.required as boolean) // type assertion needed for `group` fields
65+
}
66+
/>
67+
)
5268
}

0 commit comments

Comments
 (0)