Learn how to create visually appealing and functional forms in React using Styled Components. Explore the advantages, design considerations, validation logic, and advanced techniques for building robust forms.
Creating visually appealing and functional forms in React can be challenging. Most developers would agree that balancing code structure, validation logic, and intuitive design takes effort.
Luckily, Styled Components makes crafting React forms more manageable. This post will demonstrate an accessible Styled Components form template that handles:
- Responsive layout and styling
- Built-in validation with Yup
- Reusable UI components
- Integration with frameworks like Next.js and Gatsby
In short, you'll have a production-ready form to quickly build forms that convert.
We'll start by exploring the advantages of Styled Components for forms, then walk through a complete code example. You'll learn:
- Initial setup with Styled Components
- Design considerations for accessibility
- Implementing validation logic
- Advanced techniques like props, attrs, and variables
- Using Styled Components across popular React frameworks
By the end, you'll have a reusable Styled Components form foundation to streamline development.
Introduction to Styled Components in React Forms
Styled components is a popular CSS-in-JS library that allows you to write component-scoped CSS using JavaScript template literals. It can help create readable, maintainable forms in React apps.
The goal of this guide is to demonstrate simple form building with styled components following best practices like:
- Structuring for modularity and reusability
- Input validation
- Accessible and mobile-friendly UX
We'll build a basic contact form in React using features like:
- Template literal styles
- Custom CSS properties
- Polymorphic
as
prop - Passing props
- Attribute selectors
By the end, you'll have a solid foundation for leveraging styled components to create functional, resilient React forms.
Understanding CSS-in-JS with Styled Components
Styled components lets you write actual CSS code using JavaScript template literals. This allows component-scoped styling, away from traditional global CSS files. Some key advantages:
- No name collisions - unique class names get auto-generated
- Code splitting - no unused styles in the final bundle
- Easier deletion - no side effects when removing a component
- Painless maintenance - styles live next to components using them
It's a popular CSS-in-JS tool as it doesn't require learning a special syntax. You simply write normal CSS.
Advantages of Styled Components for React Forms
Compared to global CSS, styled components offers useful benefits when building React forms:
- Scoped styles - no accidental breakage across components
- Reusable - extract and share common styles
- Modular - import only what each component needs
- Dynamic - adapt based on props, themes, device sizes etc.
This improves long term maintainability of forms vs using global CSS files.
Setting the Scene for a Styled Components Form Example
In this guide, we'll build out a simple contact form with fields for name, email and message. Goal is to cover core techniques like:
- Passing props for dynamic styles
- Modular structure for reusability
- Client-side validation for UX
- Mobile-friendly responsive form
By the end, you'll know how to leverage styled components for creating readable, robust React forms.
Initial Setup for a Styled Components Form in React
Creating the App.js Structure with Styled Components
To start, we need an App.js file that will contain our main React application logic and routing. This is where we'll wrap our <Form>
component that uses styled-components.
Here's an example App.js structure:
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Form from "./Form";
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Form />} />
</Routes>
</Router>
);
}
export default App;
This wraps the <Form>
component in React router so we can access it on the homepage route.
Importing Styled Components and Form Dependencies
In our Form.js file, we need to import styled-components along with any other libraries we'll use for handling form logic and validation:
import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import styled from "styled-components";
This imports React, react-hook-form, Yup for schema validation, and styled-components so we can start building our form styles.
Drafting the Basic Form Structure in Form.js
With our imports set up, here is an example basic structure for Form.js:
const Form = () => {
return (
<StyledForm>
// Form fields and logic here
</StyledForm>
);
};
const StyledForm = styled.form`
// Styles here
`;
export default Form;
This creates a Form component that wraps form elements in a <StyledForm>
wrapper to apply styled-components styles.
We can now start adding form fields, validation, and styling using styled-components in a React form.
Designing Form Styles with Styled Components
Setting a Container with Max-Width Using Styled Components
To center align the form and set an appropriate max-width for readability on all viewports, we can create a Container component with styled-components:
const Container = styled.div`
max-width: 600px;
margin: 0 auto;
padding: 2rem;
`;
The max-width keeps the form content constrained, while margin auto centers it. The padding adds breathing room around the form.
Applying Normalize CSS to Form Elements
It's important to apply normalize CSS reset styles so form elements render consistently across browsers:
const Input = styled.input`
box-sizing: border-box;
margin: 0;
padding: 0.5rem;
`;
This ensures padding, margins and box model behavior is consistent.
Styling Input Fields with Consistency and Accessibility
We can build on the base input component to add visual styles:
const Input = styled.input`
border: 1px solid #ccc;
border-radius: 4px;
&:focus {
outline: 2px solid blue;
}
`;
The borders, border-radius and focus outline improve usability.
Creating Interactive Buttons with Styled Components
Buttons should have a pointer cursor and hover effect:
const Button = styled.button`
cursor: pointer;
&:hover {
background: blue;
color: white;
}
`;
This signals interactivity to the user.
Displaying Error Messages with Clear Visibility
We can style error messages to stand out:
const ErrorText = styled.div`
color: red;
margin-top: 0.5rem;
`;
The red color draws attention, while the margin spacing ensures other elements don't visually collide with the text.
sbb-itb-bfaad5b
Implementing Form Logic and Validation in React
Defining Input Validation Schema with Yup
To validate inputs in a React form built with styled components, we can create a validation schema using Yup. This allows us to define things like:
- Required fields
- Email format
- Password complexity rules
- And more
Here is an example schema for a login form:
import * as yup from 'yup';
const schema = yup.object().shape({
email: yup.string().email('Invalid email').required('Email is required'),
password: yup.string()
.min(8, 'Password must be at least 8 characters')
.required('Password is required'),
});
We can then pass this schema into React Hook Form's useForm()
hook as we'll see next.
Initializing useForm Hook with Styled Components
To handle form state and validation, we'll use React Hook Form's useForm()
hook. Here is an example initialization:
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { schema } from './schema';
const defaultValues = {
email: '',
password: '',
};
const { register, handleSubmit } = useForm({
defaultValues,
resolver: yupResolver(schema),
});
We pass the schema to a Yup resolver so validations are run against it. The register()
function is used in the inputs.
Handling Form Submission with Styled Components
When the form is submitted, we can run validations and handle the results:
const onSubmit = async (data) => {
try {
// Call API or handle form data
reset(); // Clear form
} catch (error) {
console.log(error);
}
}
const { handleSubmit } = useForm();
<Form onSubmit={handleSubmit(onSubmit)}>
{/* Form inputs */}
<Button type="submit">Login</Button>
</Form>
If validation fails, the errors will be surfaced automatically. If it succeeds, we can process the data and clear the form.
Conditionally Displaying Error Messages
To display any validation error messages, we can use React Hook Form's formState
property:
const {
register,
formState: { errors }
} = useForm();
return (
<Form>
<Input {...register('email')} />
{errors.email && <Error>{errors.email.message}</Error>}
<Button type="submit">Submit</Button>
</Form>
);
Here we check if there are any errors for the email input and display the message if so. This allows handling errors for each input separately.
Advanced Styled Components Techniques for Forms
Dive into more complex aspects of styled-components, such as props, attrs, and selectors, and how they can be utilized in form design.
Leveraging Styled-Components Props in Form Elements
Styled components allow you to pass props to style elements dynamically. For example, you can create a FormInput component and pass a size
prop to change the height:
const FormInput = styled.input`
height: ${props => props.size === 'large' ? '48px' : '36px'};
`
<FormInput size="large" />
This helps reduce code duplication. You can also pass complex objects via props and access the values:
const theme = {
colors: {
primary: 'blue'
}
}
const FormInput = styled.input`
border: 1px solid ${props => props.theme.colors.primary};
`
<FormInput theme={theme} />
Utilizing the Styled-Components attrs Constructor
The attrs
constructor allows you to set default attributes on elements:
const FormInput = styled.input.attrs({
type: 'text',
required: true
})`
// styles
`
<FormInput /> // type="text" required
This reduces repetitive code when setting common attributes.
Applying CSS Custom Properties with Styled Components
You can create CSS custom properties (variables) that can be reused across styled components:
const vars = css`
--colorPrimary: hotpink;
`
const FormLabel = styled.label`
&:after {
content: "*";
color: var(--colorPrimary);
}
`
<FormLabel />
This allows consistent theming across components.
Creating Polymorphic Props for Reusable Form Elements
The as
polymorphic prop allows you to dynamically change the HTML tag rendered by a component while retaining its styling:
const FormElement = styled.input`
display: block;
// shared styles
`
<FormElement as="select" />
<FormElement as="textarea" />
This creates reusable base components where only the tag changes.
Handling Vendor Prefixes and Style Normalization
Libraries like polished
help handle vendor prefixes:
import { normalize, transitions } from 'polished'
const FormButton = styled.button`
${normalize()}
${transitions(['background'], '0.3s')}
`
You can also create a global NormalizeStyles component for normalization across browsers.
Integrating Styled Components with Frameworks
Styled components can be seamlessly integrated with popular JavaScript frameworks like Next.js and Gatsby to style forms. Here are some tips for usage with each:
Usage of Styled Components with Next.js Forms
To use styled components with a Next.js form:
- Install the
styled-components
andbabel-plugin-styled-components
packages - Configure Babel to use the styled components plugin
- Import styled components in your pages/components
- Style form elements using template literals
For example:
import styled from 'styled-components';
const Form = styled.form`
max-width: 500px;
background: white;
padding: 20px;
`;
export default function ContactForm() {
return (
<Form>
// form elements
</Form>
)
}
Benefits of this approach:
- Automatic vendor prefixing
- Server-side rendering support
- Theming capabilities
- Styling abstraction from components
Leveraging Styled Components in Gatsby Forms
Similar steps can be followed to use styled components with Gatsby:
- Install styled components and the babel plugin
- Configure the Gatsby babel config
- Restart the dev server
- Import and use styled components
For example:
import styled from 'styled-components';
const FormWrapper = styled.div`
font-family: 'Arial';
form {
background: papayawhip;
}
`;
export default function Contact() {
return (
<FormWrapper>
<form>
// form fields
</form>
</FormWrapper>
)
}
Benefits for Gatsby:
- Theming and styling abstraction
- Works with Gatsby SSR
- Code splitting automatically handled
- High performance
So in summary, styled components integrate smoothly with both Next and Gatsby for crafting form UIs, providing useful capabilities on top of those frameworks.
Conclusion: Crafting Forms with Styled Components in React
Summarizing the Styled Components Form Example
Here are some key takeaways from this guide on creating forms with styled components in React:
-
Styled components allow you to write actual CSS code to style your components. This makes it easy to create reusable and modular styles.
-
Using React Hook Form along with Yup for validation keeps the form logic separate from the UI code. This results in better organized and maintainable forms.
-
Focusing on the user experience with things like clear labels, validation messages, and a simple layout leads to better conversion rates.
-
Styled components has features like props and attrs that make dynamic styling simple. You can update CSS values based on component props.
-
Following best practices like normalize CSS, using CSS custom properties, adding vendor prefixes, etc. makes your forms robust and consistent across browsers.
Overall, styled components enables crafting scalable, dynamic forms that provide a great user experience.
Further Learning and Documentation for Styled Components
To learn more about building forms with styled components and React, refer to these additional resources:
- Styled Components Docs - Official documentation with examples for all features
- React Hook Form - Examples and API reference for this form validation library
- Yup Documentation - Details on schema validation with Yup
- React Forms Overview - React's form documentation covering handling submissions, validation, etc.
The styled components documentation in particular has extensive examples for dynamic styling, global styles, server-side rendering, and more that are useful for building React forms.