Building a React component library with styled-components: Input Field

The TextField component we are going to create as shown on my CodePen demo / GitHub demo

Getting Started

Since this is an article about building a component library for a React app, the prerequisites are: basic knowledge of ES6, React, JSX, Webpack, and npm/yarn.

npm install --save styled-components
OR
yarn add --dev styled-components
.
├── ...
├── components # components files
│ ├── TextField # TextField component
│ ├── styles.js # styled-component styles
│ ├── index.js # React class
│ └── test.js # unit tests for component code
│ ├── Dropdown # Dropdown component
│ ├── styles.js # styled-component styles
│ ├── index.js # React class
│ └── test.js # unit tests for component code
│ └── AnotherComponent # similar structure as above
├── src # components files
│ ├── Form # form page
│ ├── styles.js # styles specific to the page
│ ├── index.js # React class
│ └── test.js # unit tests for the page
├── css # folder for .css files
│ └── main.css # global CSS
├── app.js # the root that mounts the app
├── index.html # the HTML page for the SPA
└── ...

./src/app.js

This is the simplest setup for the entry JavaScript file with React, JSX, and Webpack.

import React from "react";
import ReactDOM from "react-dom";
import { Form } from "./src/Form";
ReactDOM.render(
<Form />,
document.getElementById("root")
);

./src/main.css

For the blue background and centering the elements as shown on my CodePen demo, this is the global CSS we are including.

* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
background-color: #b4edff;
font-family: Lucida Grande, Calibri;
padding: 20px;
margin: 0;
}

How to create styled components

Before we start working on the styled-components, let’s do a brief introduction on how to use it.

./components/TextField/styles.js

For all styles specific to this component, we would put it in the styles file under its component folder.

import styled from 'styled-components';const Text = styled.p`
margin: 8px auto;
`
const Error = styled(Text)`
font-size: 12px;
color: red;
`
const StyledInput = styled.input`
width: 100%;
font-size: 14px;
padding: 6px 8px;
border-width: 1px;
border-style: solid;
border-color: ${props => props.error ? 'red' : 'black'};
margin: 0;
`
export {
Text,
Error,
StyledInput
};

./components/TextField/index.js

On the actual component file, we import the styles defined for this component, and then we define the React component in this file. There are two ways to declare the React component:
1) use class React extends React.Component {} to create a typical React component, OR
2) use styled-components to create a styled React component

import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Text, Error, StyledInput } from './styles';
const TextField = styled(({
id,
name,
value,
placeholder,
hasError,
isTouched,
hintText,
type,
onChange,
disabled,
className
}) => {
const error = isTouched && hasError;
return (
<div className={className}>
<StyledInput
id={id}
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
disabled={disabled}
error={error}
/>
{hintText && <Text>{hintText}</Text>}
{error && <Error>{error}</Error>}
</div>
)
})``
TextField.propTypes = {
id: PropTypes.string,
value: PropTypes.string,
placeholder: PropTypes.string,
error: PropTypes.string,
hintText: PropTypes.string,
type: PropTypes.string,
onChange: PropTypes.func,
disabled: PropTypes.bool,
className: PropTypes.string
};
export {
TextField
};

./src/Form/styles.js

These are the styles specific to the Form page.

import styled from 'styled-components';import { TextField } from '../../components/TextField/';const StyledTextField = styled(TextField)`
border-width: 2px;
border-style: dashed;
border-color: #1166ff;
box-shadow: 0 4px 4px #1166ff;
outline: none;
`
const FormRow = styled.div`
width: 500px;
margin: 20px auto;
`
export {
StyledTextField,
FormRow
};

./src/Form/index.js

Here we need a stateful component in the app to manage / control the values of the TextFields. The TextFields field1 and field2 are controlled components, and field3 is an uncontrolled component. In general, we would like all our React form components to be controlled.

import React from 'react';import { Text } from '../../components/TextField/styles';
import { TextField } from '../../components/TextField/';
import { StyledTextField, FormRow } from './styles';
class Form extends React.Component {
state = {
values: {
field1: "Yeah I am a reusable component!",
field2: ""
}
}
onChange = event => {
const newValuesObj = Object.assign({}, this.state.values, {[event.target.name]: event.target.value});
this.setState({
values: newValuesObj
});
}
render() {
return (
<React.Fragment>
<FormRow>
<TextField
name="field1"
type="text"
value={this.state.values.field1}
placeholder="Sexy Controlled Text Field"
onChange={this.onChange}
/>
<Text>
<span>New Value: </span>
<span>{this.state.values.field1}</span>
</Text>
</FormRow>
<FormRow>
<TextField
name="field2"
type="text"
value={this.state.values.field2}
placeholder="I have an error!"
hasError="This is a required field!"
onChange={this.onChange}
isTouched
/>
</FormRow>
<FormRow>
<StyledTextField
name="field3"
type="text"
placeholder="I know I am special yeahhhh baby"
/>
</FormRow>
</React.Fragment>
)
}
}
export {
Form
};

Front-end developer. I ❤ CSS & JavaScript. My brain occasionally runs out of memory so I need to pen down my thoughts.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store