Building a Custom Color Picker Component with MUI and React-Color
In modern web applications, integrating a robust and user-friendly color picker can significantly enhance the user experience. This is especially true for design tools, customizable theme interfaces, and other interactive applications. In this blog post, we’ll walk you through creating a custom MUI Color Picker component using Material-UI (MUI) and React-Color.
The MUI Color Picker component we will build leverages Material-UI for the UI elements and React-Color for the color selection functionality. This combination allows us to create a seamless, visually appealing, and accessible color picker.
Here’s the complete code for the MUI Color Picker component:
import {
FormControl,
IconButton,
InputAdornment,
Popover,
TextField,
Typography,
} from "@mui/material";
import { useState, Fragment } from "react";
import PropTypes from "prop-types";
import { SketchPicker } from "react-color";
import SquareIcon from "@mui/icons-material/Square";
// The ColorPicker component allows users to select and input a color in hex format.
// It uses MUI for the UI elements and React-Color for the color picker functionality.
export default function ColorPicker({ hexColor, setHexColor }) {
// State to manage the anchor element for the popover
const [anchorEl, setAnchorEl] = useState(null);
// State to track if there's an error in the hex input
const [error, setError] = useState(false);
// Handle the opening of the popover when the color icon is clicked
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
// Handle the closing of the popover
const handleClose = () => {
setAnchorEl(null);
};
// Determine if the popover is open based on the presence of an anchor element
const open = Boolean(anchorEl);
// Assign a unique ID to the popover for accessibility purposes
const id = open ? "color-picker-popover" : undefined;
// Handle color changes from the SketchPicker component
const handleColorChange = (selectedColor) => {
const newHexColor = selectedColor.hex;
setHexColor(newHexColor);
};
// Handle changes in the hex input field
const handleHexInputChange = (event) => {
const inputColor = event.target.value;
setHexColor(inputColor);
// Validate the hex color input
if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(inputColor)) {
setError(false); // Valid hex color
} else {
setError(true); // Invalid hex color
}
};
return (
<Fragment>
{/* Form control to wrap the text field */}
<FormControl fullWidth>
{/* Label for the color picker */}
<Typography component="label" mb={1} htmlFor="color-picker-input">
Color Picker
</Typography>
{/* Text field for hex color input */}
<TextField
id="color-picker-input"
value={hexColor}
onChange={handleHexInputChange}
InputProps={{
// End adornment with an icon button to open the color picker
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={handleClick} aria-describedby={id} aria-label="select color">
{/* Icon to show the current color */}
<SquareIcon sx={{ color: hexColor }} />
</IconButton>
</InputAdornment>
),
}}
error={error} // Display error state if the input is invalid
helperText={error ? "Invalid Color" : ""} // Helper text for error message
/>
</FormControl>
{/* Popover for the SketchPicker component */}
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
{/* SketchPicker component for color selection */}
<SketchPicker color={hexColor} onChange={handleColorChange} />
</Popover>
</Fragment>
);
}
// PropTypes to validate props passed to the ColorPicker component
ColorPicker.propTypes = {
hexColor: PropTypes.string.isRequired, // hexColor must be a string
setHexColor: PropTypes.func.isRequired, // setHexColor must be a function
};
Step-by-Step Breakdown
- Imports and Initial Setup:
- We import necessary components from MUI, React, and React-Color.
useState
is used for managing component state, such as the color value and error state.
- Component Definition:
- The
ColorPicker
function is defined, acceptinghexColor
andsetHexColor
as props. - PropTypes are used to ensure these props are passed correctly.
- The
- State Management:
anchorEl
is used to manage the popover’s position.error
tracks whether the current hex input is valid.
- Event Handlers:
handleClick
andhandleClose
manage the opening and closing of the color picker popover.handleColorChange
updates the color state when a new color is selected.handleHexInputChange
updates the color state based on text input and validates the hex value.
- Rendering the Component:
- A
FormControl
contains the label andTextField
. - The
TextField
includes anInputAdornment
with anIconButton
that displays the current color. - A
Popover
contains theSketchPicker
from React-Color, allowing users to pick a color visually.
- A
- PropTypes Validation:
- We ensure
hexColor
is a string andsetHexColor
is a function.
- We ensure
Accessibility and User Experience Enhancements
- ARIA Attributes: Added
aria-describedby
andaria-label
to improve accessibility. - Error Handling: Visual feedback for invalid hex color inputs.
- Dynamic Icon Color: The color of the
SquareIcon
dynamically reflects the current color value.
Conclusion
By combining the power of MUI for the UI components and React-Color for the color picker, we have created a robust, accessible, and user-friendly custom MUI Color Picker. This component can easily be integrated into any React application to allow users to select and input colors effectively.
Feel free to customize and extend this MUI Color Picker component further based on your application’s needs. Happy coding!
If you found this guide helpful, consider sharing it with your network or following our blog for more tutorials on building modern web applications with React and MUI. Let us know in the comments how you’re using the MUI Color Picker in your projects!
About the author
Alok Jain
As a Frontend Developer and Founder, I blend technical skills with entrepreneurial drive. Skilled in crafting intuitive user interfaces, I bridge design and development for seamless digital experiences. Beyond work, I'm passionate about Philately, sharing my collection, and connecting with fellow enthusiasts in both tech and stamp collecting communities.