Reputation: 6991
I am creating a form Component that will have a Form
component and an Input
component. Something like this:
<Form>
<Input name="name" />
<Input name="email" />
</Form>
In my setup, labels are automatically get generated from the name
prop. What I would like to do, though, is provide an option to not show labels. Now, I could do it on each <Input>
component like this:
<Form>
<Input noLabel name="name" />
<Input noLabel name="email" />
</Form>
But what I would really like to do is add it to the <Form>
component and have it automatically applied to each <Input>
component. Something like this:
<Form noLabel>
<Input name="name" />
<Input name="email" />
</Form>
The way I envision it, when defining my <Input>
component I could do a check if the noLabel prop is set on the <Form>
component. Something like this:
export const Input = props => {
...
{!props.noLabel && <label>...}
<input.../>
...
}
But I can't figure out how to get access to the noLabel
prop from the <Form>
component so that I can check to see whether or not it is set.
Any ideas on how to do this?
Upvotes: 1
Views: 103
Reputation: 14375
I would choose the context approach, to overcome the problems I mentioned in my comment to Mohamed's solution, this would enable indirect nesting as well:
const FormContext = React.createContext();
const Form = ...;
Form.Context = FormContext; // or simply Form.Context = React.createContext();
export default ({noLabel, ...props}) => <FormContext.Provider value={{noLabel}}/>;
and then your input component will consume it either like this:
const Input = props => {
const {noLabel} = useContext(Form.Context);
return (... < your no label logic here > ...);
}
or like this:
const Input = ....;
export default props => () => {
const {noLabel} = useContext(Form.Context);
return <Input noLabel={noLabel}/>
}
Upvotes: 2
Reputation: 21297
One way to do it is manipulating form
's children
. Mapping over each one and inject noLabel
prop
. You still will need to check inside Input
for a noLabel
prop
but it's definitely less work
const Form = ({children, noLabel}) =>{
return React.children.forEach(_, child =>{
return React.cloneElement(child, { noLabel })
})
}
Upvotes: 2
Reputation: 12691
In your Form
component, you can use React.Children
and React.cloneElement
to pass the noLabel
prop to the input components, something like this :
const children = React.Children.map(this.props.children, child =>
React.cloneElement(child, { noLabel: this.props.noLabel })
);
return (<form>{children}</form>);
Upvotes: 2