How to Build User-Friendly Forms Using Chakra UI in React
Styling applications with custom CSS is all fun until a project grows in complexity. The challenge lies in styling and maintaining a consistent design throughout the application.
While you can still use CSS, it’s often more effective to use a UI-styling library like Chakra UI. This library provides a quick and hassle-free way of styling your apps using pre-defined UI components and utility props.
Getting Started With Chakra UI in React Applications
To get started with Chakra UI, go ahead and, scaffold a basic React application using the create-react-app command. Alternatively, you can use Vite to create a React project.
Next, install these dependencies:
npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion You can find this project's code in its GitHub repository.
Add Chakra's Theme Provider
After you’ve installed these dependencies, you need to wrap the application with the ChakraProvider. You can add the provider either in your index.jsx, main.jsx, or App.jsx as follows:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { ChakraProvider } from '@chakra-ui/react'ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<ChakraProvider>
<App />
</ChakraProvider>
</React.StrictMode>,
)
Wrapping the application with the ChakraProvider is necessary to access Chakra UI's components and styling properties throughout your application.
Toggle Different Themes
Chakra UI provides a default pre-built theme that includes support for light, dark, and system color modes. However, you can further customize your application's UI themes and other style properties within a theme object as specified in Chakra's documentation.
To toggle the dark and light themes, create a components/ThemeToggler.jsx file in the src directory and include the following code.
import React from 'react'
import { useColorMode, Box, IconButton} from '@chakra-ui/react';
import { SunIcon, MoonIcon } from '@chakra-ui/icons'export default function ThemeToggler() {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Box textAlign="center" py={4} >
<IconButton
icon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
onClick={toggleColorMode}
variant="ghost"
/>
<h2>Toggle Theme</h2>
</Box>
);
}
Now, go ahead, and import the icons package:
npm i @chakra-ui/icons The ThemeToggler component will render a button that lets users switch between light and dark themes in the app.
This component accesses the current color mode the useColorMode hook and uses the toggleColorMode function to switch between modes.
The IconButton component takes on the characteristics of an icon while also having the clickable capabilities of a button.
Create a Login Form UI
Create a new Login.jsx file in the components directory, and add the following code to it:
First, add these imports.
import React, { useState } from 'react';import {
Box,
Button,
Card,
CardBody,
Center,
Flex,
FormControl,
FormLabel,
Heading,
HStack,
Input,
Stack,
VStack,
useColorMode,
} from '@chakra-ui/react';
After importing these UI components, define the React functional component and the main container components that will hold all the elements for the login user interface.
function Login() {
const { colorMode } = useColorMode(); return (
<Box>
<Flex justify="center" align="center" height="80vh" >
<Center>
<Stack>
</Stack>
</Center>
</Flex>
</Box>
);
}
export default Login;
The Box component renders a div element—it serves as the base building block on top of which you build all other Chakra UI components. Flex, on the other hand, is a Box component with its display property set to flex. This means you can use the flex properties to style the component.
Both Center and Stack components are layout components, however, they have slight differences in functionality. The center component is responsible for aligning all child components at its center, while Stack, groups UI elements together and adds spacing between them.
Now, let's build the header section of the form. The Header component will be really helpful for this part. Inside the Stack component, add this code.
<VStack spacing='6'>
<Heading
fontWeight='500'
fontSize='30px'
letterSpacing='-0.5px'
>
Login
</Heading>
</VStack> The VStack component stacks its child elements in the vertical direction. Next, create the card component that will house the login form and its elements.
<Card bg='#f6f8fa' variant='outline' borderColor='#d8dee4' w='308px'
size="lg" borderRadius={8} boxShadow="lg"
>
<CardBody>
<form>
<Stack spacing='4'>
<FormControl isRequired>
<FormLabel size='sm'
color={colorMode === 'dark' ? 'black' : 'black'}
>Email Address</FormLabel> <Input
type='text'
bg='white'
borderColor='#d8dee4'
size='sm'
borderRadius='6px'
color={colorMode === 'dark' ? 'black' : 'black'}
value={email}
/>
</FormControl>
<FormControl isRequired>
<HStack justify='space-between'>
<FormLabel size='sm'
color={colorMode === 'dark' ? 'black' : 'black'}
>Password</FormLabel>
<Button
as='a'
href='#'
variant='link'
size='xs'
color='#0969da'
fontWeight='500'
>
Forgot password?
</Button>
</HStack>
<Input
type='password'
bg='white'
borderColor='#d8dee4'
size='sm'
borderRadius='6px'
color={colorMode === 'dark' ? 'black' : 'black'}
value={password}
/>
</FormControl>
<Button
type="submit"
bg='#2da44e'
color='white'
size='sm'
_hover={{ bg: '#2c974b' }}
_active={{ bg: '#298e46' }}
>
Sign in
</Button>
</Stack>
</form>
</CardBody>
</Card>
Go ahead and update your App.jsx file to import the Login, as well as the ThemeToggler component.
import React from 'react'
import Login from './components/login'
import ThemeToggler from './components/ThemeToggler'export default function App() {
return (
<div>
<ThemeToggler />
<Login />
</div>
)
}
Great! Start the development server to update the changes.
npm run dev Now, once the page loads on the browser, it will initially display the default light mode theme.

Now, click the Toggle Theme icon button to switch the theme mode.

Managing Form State Using React Hooks
At this point, the login form only contains two input fields and a sign-in button. To make it functional, let's start by implementing state management logic using React hooks.
Define the following states inside the Login functional component.
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [success, setSuccess] = useState('');
const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false); Next, add the onChange handler function that will listen to changes to the input fields, capture the inputs, and update the email and password states accordingly.
Add these code statements to the input fields.
onChange={(e)=> { setEmail(e.target.value)}}
onChange={(e)=> { setPassword(e.target.value)}} With these changes, you now capture user inputs.
Implementing Form Validation and Error Handling With Chakra UI’s Built-In Features
Now, add a handler function that will process the inputs and return appropriate results. On the form element opening tag, add the onSubmit handler function as follows.
<form onSubmit={handleSubmit}> Next, define the handleSubmit function. Right below the states you have defined, include the following code.
const handleSubmit = async event => {
event.preventDefault();
setIsLoading(true); try {
await userLogin({ email, password });
setSuccess('Logged in successfully!');
setIsLoading(false);
setIsLoggedIn(true);
} catch (error) {
setError('Invalid username or password!');
setIsLoading(false);
setEmail('');
setPassword('');
}
};
This asynchronous handleSubmit function will trigger when someone submits the form. The function sets the loading state to true—simulating a processing action. You can render Chakra UI's loading spinner to provide a visual cue to the user.
Moreover, the handleSubmit function will call the userLogin function which takes in the email and password as parameters to validate them.
Simulate an Authentication API Request
To verify that the inputs provided by a user are valid, you can simulate an API call by defining the userLogin function which will verify the login credentials similar to how a backend API would.
Right below the handleSubmit function, add this code:
const userLogin = async ({ email, password }) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (email === 'test@email.com' && password === 'password') {
resolve();
} else {
reject();
}
}, 1000);
});
}; This code defines an asynchronous function that performs a simple logic validation logic.
Chakra's Error Handling UI Features.
You can provide suitable visual feedback to users based on their interactions on the form by using Chakra's feedback components. To do that, start by importing these components from Chakra's UI library.
Alert, AlertIcon, AlertTitle, CircularProgress Now, add the following code right below the form element opening tag.
{error && !isLoggedIn &&
<Alert status='error' variant='solid'>
<AlertIcon />
<AlertTitle>{error}</AlertTitle>
</Alert>
}
{isLoggedIn && (
<Alert status="success" variant='solid'>
<AlertIcon />
<AlertTitle>{success}</AlertTitle>
</Alert>
)} Finally, make this update to the submit button to include the loading spinner, CircularProgress, component.
{isLoading
? (<CircularProgress isIndeterminate size="24px" color="teal" />)
: ('Sign In')} Here is what a user will see once they log in successfully:

If there is an error in the login process, they should see a response like this:
Improve Your Development Process With Chakra UI
Chakra UI provides a set of well-designed and customizable UI components that you can use to quickly build React UIs. Regardless of how simple or complex your designs are, Chakra has components for almost all UI tasks.
ncG1vNJzZmivp6x7rq3KnqysnZ%2Bbe6S7zGiaoZmbp65uwchmqZ6Zk6l6p7vRpqpmraOav26y0aKcp5ycrnw%3D