01 Text Field | Building 🚧 Dock-UI: Custom Tailwind CSS components for H010SPACE
Tags: tailwindcss, css
Published: 2021-11-18 15:55:16

> Every since I was introduced to Tailwind CSS - A utility-first CSS framework - I have wanted to build my own flavor of custom UI components with it. Even with so many wonderful UI component frameworks and libraries out there, some may have a few component styles I like, but none have all and only the components I like / find useful.

> So, I have decided to document building a complete set of my own custom components called Dock-UI.

While H010SPACE is in development, the only accessible page for awhile will be the landing page which has one main element, a sign up `<form />` for the mailing list with a email `<input />` and submit `<button />`.

**So, first up we're building an `<input />` with [Tailwind CSS](https://tailwindcss.com/)**. 

Of all the frameworks and libraries I've seen so far, my favorite style for `<input />` is by [Material Design](https://material.io/components/text-fields). Today we'll build the Material Design Filled Text field with Tailwind CSS.

*Note: I usually use [Windi CSS](https://windicss.org/) instead of Tailwind CSS for the speed ⚡, but the classes work the exact same for both.*

Starting with the foundation we have:

```
<input type="email" placeholder="E-Mail" class="border" />  
```

Now that we have the base lets style it up. According to Material Design the [anatomy](https://material.io/components/text-fields#anatomy) of a text field consists of:

1. Container
2. Leading icon (optional)
3. Label text
4. Input text
5. Trailing icon (optional)
6. Activation indicator
7. Helper text (optional)

```
<div>
    <label for="email">E-Mail</label>
    <input type="email" name="email" class="border" />
</div>
```

For simplicity I've left out the *optional* bits.

**TL;DR** the finished code is right below take it, use it, and modify the crap 💩 out of it. A brief explanation of the code will follow if you want to stick around for it.

**HTML**
```
<div class="d-textfield relative bg-black bg-opacity-10 px-4 pt-5 pb-1.5 rounded-t border-b border-black border-opacity-40">
    <input type="email" name="email" placeholder=" " class="block bg-transparent w-full appearance-none focus:outline-none text-sm" />
    <label for="email" class="absolute top-0 transform translate-y-1/2 duration-300">E-Mail</label>
</div>
```

**SCSS**
```
.d-textfield:focus-within {
  border-bottom: 2px solid blue;
  background-color: rgba(0,0,0, 0.20) !important;
  & input {
    caret-color: blue;
  }
  & label {
    color: blue;
  }
}

.d-textfield label {
  z-index: -1;
}

.d-textfield input:focus-within ~ label,
.d-textfield input:not(:placeholder-shown) ~ label {
  //@apply transform scale-75 -translate-y-6;
  transform: translate(-0.4em) scale(0.74);
}

```
{% codepen https://codepen.io/shecodez/pen/zYdyXOK %}

Part of the beauty of Tailwind CSS is that the utility classes make it pretty clear what's going on. Plus because you can extend tailwind the SCSS can be made even shorter.

For example we can change the border color when the input is focused using the pseudo-class `focus-within`. We can enable the focus-within variant in Tailwind for `borderColor` by adding it in the `tailwind.config.js` or `windi.config.js` under the variants section:

**tailwind.config.js** / **windi.config.js**
```
variants: {
  borderColor: ['responsive', 'hover', 'focus', 'focus-within'],
}
```

Then we can add the `focus-within:border-blue-500` class to the input container `<div />` to change the border color on focus and remove  the `.d-textfield:focus-within { border-bottom: 2px solid blue; }` from the SCSS.

The same thing could be done with the negative `z-index` for the `<label />`. Just extend the Tailwind theme to generate a negative z-index for you:

**tailwind.config.js** / **windi.config.js**
```
theme: {
  extend: {
    zIndex: {
      "-1": "-1",
    },
  },
}
```

With that you can add the class `-z-1` to the `<label />`, and remove `.d-textfield label { z-index: -1; }` from the SCSS.

And with that we've completed our first dock-ui component. Of course it's very basic right now but I leave the upgrades for you and future me. 😊  

Thanks for reading! 🖖