Reputation: 1392
I am trying to make a reusable react input element.
React version:
"react": "17.0.2"
I want to pass htmlFor
in the label and use the same in the children id
property.
So I am trying to pass props to {children}
in react.
I have tried passing props from this solution
{React.cloneElement(children, { id: label })}
My component that uses children.
import clsx from 'clsx';
import React from 'react';
import { FunctionComponent } from 'react'; // importing FunctionComponent
type FieldWrapperProps = {
children: React.ReactNode;
label: string;
errorMessage?: string;
className?: string;
};
export const FieldWrapper: FunctionComponent<FieldWrapperProps> = (props: FieldWrapperProps) => {
const { children, label, errorMessage, className } = props;
return (
<div
className={clsx('mt-6 flex flex-col justify-center tracking-wide align-middle', className)}
>
<label htmlFor={label} className="block text-gray-light text-base font-bold mb-2 peer">
{label}
</label>
{React.cloneElement(children, { id: label })}
{/* {children} */}
<p className="text-sm text-red-500 ">{errorMessage}</p>
</div>
);
};
I am using this FieldWrapper
in various other form elements like so.
import { UseFormRegisterReturn } from 'react-hook-form';
import { FieldWrapper } from './FieldWrapper';
type InputFieldProps = {
label: string;
type: string;
registration?: UseFormRegisterReturn;
error?: string;
placeholderText?: string;
className?: string;
};
export const InputField = (props: InputFieldProps) => {
const { type, label, registration, error, placeholderText, className } = props;
return (
<FieldWrapper label={label} errorMessage={error} className={className}>
<input
type={type}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id={label}
placeholder={placeholderText}
{...registration}
/>
</FieldWrapper>
);
};
Upvotes: 2
Views: 11732
Reputation: 10538
You're getting this type error because React.cloneElement()
requires an Element to clone; children
is not guaranteed to be an element. It's a ReactNode
, which is a type alias that includes undefined
and null
. Those are valid types to return from a React component, but not to pass to cloneElement
. You could do this instead:
children = React.Children.map(children, el => {
return React.cloneElement(el, { id: label })
})
This would allow you to clone each element in turn. If you only expect a single element, React.Children.only()
can be used in a similar way
children = React.Children.only(children)
children = React.cloneElement(children)
Upvotes: 4