Upleveling my form component design ⬆️
Tags: javascript, react, designsystem, devjournal
Published: 2022-10-06 08:07:59

---
title: Upleveling my form component design ⬆️
published: true
description: My ongoing journey of creating form components for my design system.
tags: javascript, react, designsystem, devjournal
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywkvsv23vc0ebk6xymat.png
# Use a ratio of 100:42 for best results.
---

When I created a design system for my app, I first had components for many elemental input elements eg. `<InputText />`, `<TextArea />`, and `<InputEmail />`.

Later I figured that I often need those in combination with a label, error message, some description and so on, pretty basic stuff. I decided to call these groups `FormField` and started to implement components like `FormFieldText` and `FormFieldEmail`.

Here is an example:

```jsx
<FormFieldPassword
  className={styles.formFieldPassword}
  autoComplete="new-password"
  label="Set a password"
  below={<FieldHelp>At least 8 characters</FieldHelp>}
  errorMessage={fieldFeedback.password}
  onChange={handleChangePassword}
  value={password}
  withShowPasswordToggle={true}
  autoFocus={emailWasInUrl}
  fullWidth
/>
```

After some time I had quite a lot `FormField…` components and a fair amount of duplicate code inside of them. Eventually I created a generic `FormField` component and used it inside of the `FormField…` components to get rid of duplicate code. This is called [composition](https://reactjs.org/docs/composition-vs-inheritance.html) and is commonly used for cases like that.

But with this approach I still had to create new `FormField…` components from time to time. I felt that skipping this step and just use the generic `FormField` component directly might be the better approach. That some Frameworks (like [Chakra UI](https://chakra-ui.com/docs/components/form-control/usage#usage)) go with a similar approach, supported my thinking.

The new approach:
```jsx
<FormField
  className={styles.formFieldPassword}
  label="Set a password"
  below={<FieldHelp>At least 8 characters</FieldHelp>}
  errorMessage={fieldFeedback.password}
>
  <InputPassword
    autoComplete="new-password"
    onChange={handleChangePassword}
    value={password}
    withShowPasswordToggle={true}
    autoFocus={emailWasInUrl}
    error={fieldFeedback.password?.length > 0}
    fullWidth
  />
</FormField>
```

What I like about this is that you can clearly see which props belong to the input. You can also directly access input props like `className` for example which is very handy. And I can add content above or below the input.

But it also creates two problems that I didn’t solve yet:

1. The input may require a different design (e.g. a red border) if an error occurs. In the example above I do this manually by setting the `error` prop of my input.

2. The label in `FormField` needs to know what input it labels. Since there can be multiple children now, it doesn't know exactly which of them is the input. Currently I'm just assuming it's the first child, but that prevents me from adding children before the input.

## Ideas for the error issue
I already have two ideas how to solve this.

One is using the [render props pattern](https://reactjs.org/docs/render-props.html) e.g.

```jsx
<FormField>
  {error => <Input error={error} … />}
</FormField>
```

I do like the flexibility of this approach. What I don’t like is how complex the markup/code looks with this solution. 

The other approach is to solve this by using a [`Context`](https://reactjs.org/docs/context.html) that can be consumed inside my input components.

The markup would be very clear as the implementation is inside of the input.

```jsx
<FormField>
  <Input />
</FormField>
```

## Ideas for the label issue
This is a tricky one. Basically, I could use either of the two approaches above.

Using the render props pattern I can generate an ID inside `FormField` and then use it like this:

```jsx
<FormField>
  {(error, labelFor) => <Input error={error} id={labelFor} … />}
</FormField>
```

But I really want the markup to look simpler. And this is where it gets trickier. Providing the generated ID in a context will come with two minor problems:

1. If there are two inputs, both will get the same ID. This doesn't seem like a big problem, but it's not allowed in the HTML specs and could cause problems.

2. If for some reason the input is assigned an `id`, the `FormField` will not know this and the label will no longer be assigned to the input.

Chakra UI seems to take this approach and in fact hasn't solved both of these problems. Maybe I am overthinking 🤔

What do you think? Do you have an idea how to solve these problems? I am happy if you leave a comment.

I will update this post if I find better solutions.