2

I want to create some form components using React. I know how to do that using pure JavaScript by createElement() and such methods, not sure how would I go about this in React.

My JSON array would look like:

[{
    "tag": "input",
    "name": "hiddenInput",
    "id": "hiddenInput",
    "type": "hidden",
    "label": "Hidden Label"
},{
    "tag": "input",
    "name": "textInput",
    "id": "textInput",
    "type": "text",
    "label": "Text Label"
}, {
    "tag": "input",
    "name": "passwordInput",
    "id": "passwordInput",
    "type": "password",
    "label": "Password Label"
}, {
    "tag": "input",
    "name": "emailInput",
    "id": "emailInput",
    "type": "email",
    "label": "Email Label"
}, {
    "tag": "input",
    "name": "phoneInput",
    "id": "phoneInput",
    "type": "text",
    "label": "Phone Label"
}, {
    "tag": "textarea",
    "name": "textarea",
    "id": "textarea",
    "label": "Textarea Label"
}, {
    "tag": "input",
    "name": "dateInput",
    "id": "dateInput",
    "type": "date",
    "label": "Date Label"
}, {
    "tag": "input",
    "name": "checkboxInput",
    "id": "checkboxInput",
    "type": "checkbox",
    "label": "Checkbox Label"
}, {
    "tag": "input",
    "name": "radioInput",
    "id": "radioInput",
    "type": "radio",
    "label": "Radio Label"
},{
    "tag": "button",
    "name": "buttonInput",
    "id": "buttonInput",
    "type": "button",
    "label": "Submit"
}];

and my desired output would be similar to:

  render() {
    return (
        <Form onSubmitStart={this.props.onSubmitStart}>
          <Input
            name="hiddenInput"
            id="hiddenInput"
            type="hidden"
            label="Hidden Label"
            value={this.state.hiddenInput}
          />

          <Input
            name="textInput"
            id="textInput"
            type="text"
            label="Text Label"
          />

          <Input
            name="passwordInput"
            id="passwordInput"
            type="password"
            label="Password Label"
          />

          <Input
            name="emailInput"
            id="emailInput"
            type="email"
            label="Email Label"
          />

          <PhoneInput
            name="phoneInput"
            id="phoneInput"
            type="text"
            country={"us"}
            enableAreaCodes={true}
            onlyCountries={["us"]}
            areaCodes={{ us: ["999","888"] }}
            inputProps={{
              name: "phone",
              country: "us",
              required: true,
              autoFocus: true
            }}
            value={this.state.phone}
            onChange={this.handlePhoneInput}
          />

        <textarea 
            name="dateInput"
            id="dateInput"
            rows={this.state.rows}
            cols={this.state.cols}
            >
        </textarea>

          <Input
            name="dateInput"
            id="dateInput"
            type="date"
            label="Date Label"
            onChange={this.handleDateInput}
          />

          <Checkbox
            name="checkboxInput"
            id="checkboxInput"
            type="checkbox"
            label="Checkbox Label"
            checked={this.state.checkbox}
          />

          <Radio
            name="radioInput"
            id="radioInput"
            type="radio"
            label="Radio Label"
            value={this.state.radio}
          />

          <Button 
            name="buttonInput"
            id="buttonInput"
            type="button"
            label="Button Label"
           > Submit </Button>
        </Form>
    );
  }

How would I do that?

Articles

JSON based dynamic forms with ReactJS

How To Create React.js Components Dynamically

(Thanks! I'm new to React framework.)

3
  • 1
    perhaps this one is closer to what you want Commented Mar 16, 2020 at 1:35
  • 1
    You can always use plain Javascript instead of JSX. Remember that JSX gets transpiled to sentences with a signature likeReact.createElement(<type>, <props>, <children>). Commented Mar 16, 2020 at 1:45
  • 1
    When I said "plain Javascript", I mean React without JSX. but the accepted answer is a really good solution! Commented Mar 16, 2020 at 13:35

1 Answer 1

2

You can map over the elements and return the appropriate element for each:

const data = [{
    "tag": "input",
    "name": "hiddenInput",
    "id": "hiddenInput",
    "type": "hidden",
    "label": "Hidden Label"
},{
    "tag": "input",
    "name": "textInput",
    "id": "textInput",
    "type": "text",
    "label": "Text Label"
}, {
    "tag": "input",
    "name": "passwordInput",
    "id": "passwordInput",
    "type": "password",
    "label": "Password Label"
}, {
    "tag": "input",
    "name": "emailInput",
    "id": "emailInput",
    "type": "email",
    "label": "Email Label"
}, {
    "tag": "input",
    "name": "phoneInput",
    "id": "phoneInput",
    "type": "text",
    "label": "Phone Label"
}, {
    "tag": "textarea",
    "name": "textarea",
    "id": "textarea",
    "label": "Textarea Label"
}, {
    "tag": "input",
    "name": "dateInput",
    "id": "dateInput",
    "type": "date",
    "label": "Date Label"
}, {
    "tag": "input",
    "name": "checkboxInput",
    "id": "checkboxInput",
    "type": "checkbox",
    "label": "Checkbox Label"
}, {
    "tag": "input",
    "name": "radioInput",
    "id": "radioInput",
    "type": "radio",
    "label": "Radio Label"
},{
    "tag": "button",
    "name": "buttonInput",
    "id": "buttonInput",
    "type": "button",
    "label": "Submit"
}];

function Form ({data}) {
  return (
    <form>
      {data.map(({tag: Cmp, ...other}) => (
        <div key={other.id}>
          {other.label}: <Cmp {...other} />
        </div>
      ))}
    </form>
  );
}

ReactDOM.render(<Form data={data}/>, document.getElementById('demo'));
form > * {
  margin-bottom: 1em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="demo"/>

Sign up to request clarification or add additional context in comments.

2 Comments

Updated to show the correct labels. You'd have to tweak it to get the label into the text of the button, but that should be trivial.
If you wanted to do something a bit more sophisticated and customize the way each type renders, you could have a mapping that chooses the appropriate react component for each entry, based on 'tag' and/or 'type'. Those components could then render whatever they want, not just a plain html input or textarea, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.