Skip to content

Commit 6d8aca5

Browse files
authored
fix(richtext-lexical): ensure nested forms do not use form element (#11462)
Previously, lexical blocks initialized a new `Form` component that rendered as `<form>` in the DOM. This may lead to React errors, as forms nested within forms is not valid HTML. This PR changes them to render as `<div>` in the DOM instead.
1 parent c828e33 commit 6d8aca5

File tree

5 files changed

+13
-4
lines changed

5 files changed

+13
-4
lines changed

packages/richtext-lexical/src/features/blocks/client/component/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ export const BlockComponent: React.FC<Props> = (props) => {
541541
return await onChange({ formState, submit: true })
542542
},
543543
]}
544+
el="div"
544545
fields={clientBlockFields}
545546
initialState={initialState}
546547
onChange={[onChange]}

packages/richtext-lexical/src/features/blocks/client/componentInline/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ export const InlineBlockComponent: React.FC<Props> = (props) => {
391391
},
392392
]}
393393
disableValidationOnSubmit
394+
el="div"
394395
fields={clientBlock?.fields}
395396
initialState={initialState || {}}
396397
onChange={[onChange]}

packages/ui/src/forms/Form/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export const Form: React.FC<FormProps> = (props) => {
6666
disableSuccessStatus,
6767
disableValidationOnSubmit,
6868
// fields: fieldsFromProps = collection?.fields || global?.fields,
69+
el,
6970
handleResponse,
7071
initialState, // fully formed initial field state
7172
isDocumentForm,
@@ -783,8 +784,10 @@ export const Form: React.FC<FormProps> = (props) => {
783784
}
784785
: {}
785786

787+
const El: 'form' = (el as unknown as 'form') || 'form'
788+
786789
return (
787-
<form
790+
<El
788791
action={typeof action === 'function' ? void action : action}
789792
className={classes}
790793
method={method}
@@ -816,7 +819,7 @@ export const Form: React.FC<FormProps> = (props) => {
816819
</FormWatchContext.Provider>
817820
</FormContext.Provider>
818821
</DocumentFormContextComponent>
819-
</form>
822+
</El>
820823
)
821824
}
822825

packages/ui/src/forms/Form/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ export type FormProps = {
2525
* you can disable checks that the form makes before it submits
2626
*/
2727
disableValidationOnSubmit?: boolean
28+
/**
29+
* If you don't want the form to be a <form> element, you can pass a string here to use as the wrapper element.
30+
*/
31+
el?: string
2832
/**
2933
* By default, the form will get the field schema (not data) from the current document. If you pass this in, you can override that behavior.
3034
* This is very useful for sub-forms, where the form's field schema is not necessarily the field schema of the current document (e.g. for the Blocks

test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,7 +1190,7 @@ describe('lexicalBlocks', () => {
11901190
// Ensure radio button option1 of radioButtonBlock2 (the default option) is still selected
11911191
await expect(
11921192
radioButtonBlock2.locator('.radio-input:has-text("Option 1")').first(),
1193-
).toBeChecked()
1193+
).toHaveClass(/radio-input--is-selected/)
11941194

11951195
// Click radio button option3 of radioButtonBlock2
11961196
await radioButtonBlock2
@@ -1201,7 +1201,7 @@ describe('lexicalBlocks', () => {
12011201
// Ensure previously clicked option2 of radioButtonBlock1 is still selected
12021202
await expect(
12031203
radioButtonBlock1.locator('.radio-input:has-text("Option 2")').first(),
1204-
).toBeChecked()
1204+
).toHaveClass(/radio-input--is-selected/)
12051205

12061206
/**
12071207
* Now save and check the actual data. radio button block 1 should have option2 selected and radio button block 2 should have option3 selected

0 commit comments

Comments
 (0)