0

I have a component that renders labels, and I pass the input elements as children as follows:

<FormGroup labelFor="my-formgroup-id">
    <input id="my-formgroup-id" /> // I don't want to duplicate this id manually here but take it from the `labelFor prop of the `<FormGroup>` it's wrapped in
</FormGroup>

How do I take that id prop/value from FormGroup and access it in the <input>?

I need the FormGroup component to render the labels and validation errors, and only want to pass different kinds of inputs (input, textarea, etc.) as children to it. However, of course the labels inside FormGroup has a for attribute to focus the right input when a corresponding label is clicked. So that's why both FormGroup and the input passed as a child element needs to know the same id.

Also I'm using functional components instead of class based.

This is what <FormGroup> looks like:

const FormGroup = (labelFor, children) => {
    <label for={labelFor}></label>
    {children}
}
erol_smsr
  • 1,454
  • 4
  • 24
  • 49
  • 1
    You might need to iterate and map all children, adjusting their props to fit your need using the [children](https://reactjs.org/docs/react-api.html#reactchildren) API. – junwen-k Nov 17 '22 at 13:24
  • I'm using id in FormGroup to pass that value to the `for` attribute of the label, not to use it in another `id` attribute. So the id's stay unique. I can rename the id prop of FormGroup to something like `labelFor` for clarity. – erol_smsr Nov 17 '22 at 13:25
  • @junwen-k Each FormGroup only has one child element, so I should iterate over a single child? – erol_smsr Nov 17 '22 at 13:26
  • Does this answer your question? [How to pass props to {this.props.children}](https://stackoverflow.com/questions/32370994/how-to-pass-props-to-this-props-children) – segFault Nov 17 '22 at 13:32
  • @segFault Not sure as that one is with class components and I use functional components. – erol_smsr Nov 17 '22 at 13:35
  • 1
    @erol_smsr The same concept can be applied to both, but the accepted answer provided is composed of functional components which should work for you. I would recommend attempting the suggestion within your `FormGroup` component using that answer as a guide, it should work for you. Specifically [look at the `Parent` component from that answer](https://stackoverflow.com/a/32371612/1514049) as it is very similar to your ask. – segFault Nov 17 '22 at 13:58
  • @segFault Yes definitely that approach seems to be the correct one. Thank you for your help. – erol_smsr Nov 17 '22 at 15:41

1 Answers1

1
const FormGroup = ({labelFor, children }) => {
   const ChildrenComponent = () =>
        React.Children.map(children, child =>
          React.cloneElement(child, {
            id: labelFor
          })
        );
    
      return <>
             <label for={labelFor}></label>
             <ChildrenComponent/>
             </>;
    };
  • Thank you, this seems great. However I get an error on `React.cloneElement(child`...` complaining about the `child` argument saying `no overload matches this call`. Any idea? – erol_smsr Nov 17 '22 at 15:35