Skip to content

Commit f8ed216

Browse files
Fix: Properly attach ref to Field's rendered input element
Previous approach tried to ref the Field component, which doesn't work. Now wrapping the render/children function to inject the ref into the actual input element that Field renders. Changes: - Renamed rootRef to fieldRef for clarity - Added findInput() helper called in componentDidMount/Update - Wrap render/children function to clone element with merged ref - Merge innerRef with fieldRef to support both internal and external refs This ensures we get access to the actual DOM input element for HTML5 validation while maintaining React 19 compatibility (no findDOMNode).
1 parent 280ce65 commit f8ed216

1 file changed

Lines changed: 37 additions & 9 deletions

File tree

src/Html5ValidationField.tsx

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react'
2-
import { Field } from 'react-final-form'
2+
import { Field, FieldRenderProps } from 'react-final-form'
33
import { Html5ValidationFieldProps } from './types'
44
import warning from './warning'
55

@@ -23,7 +23,7 @@ interface WithValidity {
2323

2424
class Html5ValidationField extends React.Component<Html5ValidationFieldProps> {
2525
private input: WithValidity | null = null
26-
private rootRef = React.createRef<HTMLElement>()
26+
private fieldRef = React.createRef<any>()
2727

2828
static defaultProps = {
2929
badInput: 'Incorrect input',
@@ -42,7 +42,17 @@ class Html5ValidationField extends React.Component<Html5ValidationFieldProps> {
4242
}
4343

4444
componentDidMount(): void {
45-
const root = this.rootRef.current
45+
this.findInput()
46+
}
47+
48+
componentDidUpdate(): void {
49+
if (!this.input) {
50+
this.findInput()
51+
}
52+
}
53+
54+
private findInput = (): void => {
55+
const root = this.fieldRef.current
4656
if (root) {
4757
let input: WithValidity | null = null
4858
if (/input|textarea|select/.test(root.nodeName.toLowerCase())) {
@@ -120,6 +130,9 @@ class Html5ValidationField extends React.Component<Html5ValidationFieldProps> {
120130
typeMismatch,
121131
valueMissing,
122132
innerRef,
133+
component,
134+
render,
135+
children,
123136
...rest
124137
} = this.props
125138

@@ -137,23 +150,38 @@ class Html5ValidationField extends React.Component<Html5ValidationFieldProps> {
137150
...fieldProps
138151
} = rest
139152

140-
// Merge innerRef with rootRef for internal use
153+
// Merge innerRef with fieldRef
141154
const mergedRef = (node: HTMLElement | null) => {
142-
// Set internal ref
143-
(this.rootRef as React.MutableRefObject<HTMLElement | null>).current = node
144-
// Call innerRef if provided
155+
(this.fieldRef as React.MutableRefObject<HTMLElement | null>).current = node
145156
if (typeof innerRef === 'function') {
146157
innerRef(node)
147158
} else if (innerRef) {
148159
(innerRef as React.MutableRefObject<HTMLElement | null>).current = node
149160
}
150161
}
151162

163+
// Wrap render function to inject ref
164+
const wrappedRender = (fieldProps: FieldRenderProps<any, HTMLElement>) => {
165+
// Call user's render/children function if provided
166+
const userRender = render || children
167+
if (userRender && typeof userRender === 'function') {
168+
const element = userRender(fieldProps)
169+
// Clone and inject ref
170+
return React.isValidElement(element)
171+
? React.cloneElement(element, { ref: mergedRef } as any)
172+
: element
173+
}
174+
// Default: render input with ref
175+
return React.createElement(component || 'input', {
176+
...fieldProps.input,
177+
ref: mergedRef
178+
})
179+
}
180+
152181
return React.createElement(Field, {
153182
...fieldProps,
154183
validate: this.validate,
155-
ref: mergedRef,
156-
component: 'input'
184+
children: wrappedRender
157185
})
158186
}
159187
}

0 commit comments

Comments
 (0)