Muhi Logo Text
AboutBlogWork With Me

Creating React Fieldset Component with MUI

Learn how to create encapsulated and reusable Fieldset component with Material UI (MUI) and React.

Last updated on August 29, 2024

react
mui
React MUI Fieldset

The <fieldset> element is a commonly used HTML element that serves a specific purpose in forms: grouping related information. For example, within a form, you might have sections like “Basic Info,” “Address,” or “Payment Info.”

When working with frameworks like React and UI libraries like MUI, using standard HTML elements directly can sometimes feel limiting. That’s where creating a custom component comes in handy. In this tutorial, we’ll walk through how to create a custom and enhanced Fieldset component using React and MUI.

Let’s dive in and start building this component step by step!

Basic React Fieldset

Let’s start by creating a basic React component named Fieldset. This component will encapsulate the HTML <fieldset> element along with its associated <legend> (the section’s title or label):

const Fieldset = ({ children }) => {
  return (
    <fieldset>
      <legend>title</legend>
      {children}
    </fieldset>
  );
};

The children prop allows you to pass in any content that should be placed inside the <fieldset>.

This is a good starting point, but it’s quite limited because the title is fixed and can’t be customized. There’s no way to pass additional properties or customize the component’s behavior.

We can enhance the Fieldset component by introducing props to make it more flexible and reusable:

  1. Customizing the Legend: We’ll introduce a title prop that allows us to dynamically modify the content of the <legend> element.
  2. Optional Legend: If no title is provided, we can disable the rendering of the <legend> element altogether.
  3. Prop Forwarding: To make our component more flexible, we’ll forward any additional props to the <fieldset> element.
const Fieldset = ({ title, children, ...props }) => {
  return (
    <fieldset {...props}>
      {title && <legend>{title}</legend>}
      {children}
    </fieldset>
  );
};

The ...props syntax (known as the rest operator) captures all additional props passed to the Fieldset component. These props are then spread onto the <fieldset> element using {...props}. This allows you to directly pass any other attributes (such as className, style, id, etc.) to the <fieldset> element from the Fieldset component.

Now that we’ve created the React component, using it is fun and straightforward! Below is an example of how it can be used within a form:

<form>
  <Fieldset title="User Information">
    <label>
      Username: <input type="text" name="username" />
    </label>
    <label>
      Password: <input type="password" name="password" />
    </label>
  </Fieldset>
</form>

Advanced MUI Fieldset

When working with MUI, you gain powerful tools for customizing styles. Thanks to the underlying theme system and the sx approaches for adding styles. Before we dive into styling, let’s first convert our previously created Fieldset React component into its equivalent MUI-based version:

import React from "react";
import { Box, Typography } from "@mui/material";

const Fieldset = ({ title, children, ...props }) => {
  return (
    <Box component="fieldset" {...props}>
      {title && <Typography component="legend">{title}</Typography>}
      {children}
    </Box>
  );
};
  • The Box component is a versatile wrapper that can take on the role of any HTML element via the component prop. In this case, we set component="fieldset" to ensure it renders as a <fieldset> in the DOM.
  • The Typography component is used to render the <legend> element. MUI’s Typography component is highly flexible and allows consistent text styling across the application.

Customizing the Component with Styling Props

To make the component more flexible, we can introduce several props that allow for easy customization of common styling properties. These include properties for controlling the border and text styling. Since the legend title and the fieldset borders often share similar colors, we can group them for convenience.

Here’s the enhanced version of our component:

import { Box, Typography } from "@mui/material";

const Fieldset = ({
  title,
  color = "inherit",
  titleSize = "1rem",
  borderWidth = 1,
  borderRadius = 2,
  children,
  sx = {},
  ...props
}) => {
  return (
    <Box
      component="fieldset"
      sx={{
        borderColor: color,
        borderWidth: borderWidth,
        borderRadius: borderRadius,
        ...sx,
      }}
      {...props}
    >
      {title && (
        <Typography
          component="legend"
          sx={{
            color: color,
            fontSize: titleSize,
          }}
        >
          {title}
        </Typography>
      )}
      {children}
    </Box>
  );
};
  • The sx prop allows you to use MUI’s design tokens and theme system directly within your components. In this example, we use sx to apply styles based on the props passed to the Fieldset component.
  • Extending sx with the spread operator (...sx) ensures that any additional styles passed to the component do not override the existing styles.
  • Using the color prop, we simplify the styling process, ensuring that the fieldset border and the legend text share the same color, which is a common requirement.

Let’s look at how to use this enhanced Fieldset component in a React application:

<Fieldset
  title="Basic Information"
  color="secondary.main"
  titleSize="1.1rem"
  borderWidth={2}
  borderRadius={1}
>
  <label>
    Username: <input type="text" name="username" />
  </label>
  <label>
    Password: <input type="password" name="password" />
  </label>
</Fieldset>

Advanced Styling with sx

While the exposed props provide a convenient way to style the component, we can further customize using the sx prop directly. This allows for more advanced and detailed styling:

<Fieldset
  title="Basic Information"
  titleSize="1.2rem"
  borderWidth={2}
  borderRadius={3}
  color="grey.400"
  sx={{
    borderStyle: "dashed",
    padding: 3,
    "& legend": {
      backgroundColor: "secondary.main",
      color: "grey.200",
      padding: "0 8px",
      borderRadius: "4px",
    },
    backgroundColor: "grey.100",
  }}
>
  {/* Form fields go here */}
</Fieldset>;

Adding Icons to the Title

The title is not limited to only text. We can pass any React element to the title prop. In the example below, we are adding an icon right before the title:

import { Typography, Stack } from "@mui/material";
import InfoIcon from "@mui/icons-material/Info";

<Fieldset
  title={
    <Stack direction="row" alignItems="center" gap={1}>
      <InfoIcon />
      Basic Information
    </Stack>
  }
  color="primary.main"
  titleSize="1.2rem"
  borderWidth={2}
  borderRadius={3}
>
  {/* Form fields go here */}
</Fieldset>;

Using TypeScript

Making the Fieldset component TypeScript-friendly brings several benefits, including reducing runtime errors, providing better autocompletion and IntelliSense in editors, and acting as self-documentation for the component.

To convert the previous Fieldset component to TypeScript, we need to create an interface that defines the types of the props and ensure that the component adheres to that interface:

import React, { ReactNode } from "react";
import { Box, Typography } from "@mui/material";
import { SxProps, Theme } from "@mui/system";

interface FieldsetProps {
  title?: ReactNode;
  color?: string;
  titleSize?: string;
  borderWidth?: number;
  borderRadius?: number;
  children: ReactNode;
  sx?: SxProps<Theme>;
}

const Fieldset = ({
  title,
  color = "grey.800",
  titleSize = "1rem",
  borderWidth = 1,
  borderRadius = 2,
  children,
  sx = {},
  ...props
}: FieldsetProps) => {
  return (
    <Box
      component="fieldset"
      sx={{
        borderColor: color,
        borderWidth: borderWidth,
        borderRadius: borderRadius,
        ...sx,
      }}
      {...props}
    >
      {title && (
        <Typography
          component="legend"
          sx={{
            color: color,
            fontSize: titleSize,
          }}
        >
          {title}
        </Typography>
      )}
      {children}
    </Box>
  );
};

export default Fieldset;

Each prop is defined in the FieldsetProps interface, and the component uses these types to ensure that the correct type of value is passed. For example, if a developer tries to pass a number to the title prop, TypeScript will throw an error.

Summary & Complete Code

In this tutorial, we created a customizable Fieldset component in React using Material-UI (MUI). Here’s a quick recap:

Basic Component: Started with a simple React component that encapsulates the <fieldset> and <legend> elements. MUI Integration: Enhanced the component by using MUI’s Box and Typography components for better styling control. Styling Flexibility: Introduced props like borderColor, borderWidth, borderRadius, and color to allow easy customization. Advanced Styling: Demonstrated the use of the sx prop for more advanced, theme-based styling. TypeScript Conversion: Converted the component to TypeScript, adding type safety and improving development with better autocompletion and documentation.

Here is the complete live code:

Bye for now 👋

If you enjoyed this post, I regularly share similar content on Twitter. Follow me @muhimasri to stay up to date, or feel free to message me on Twitter if you have any questions or comments. I'm always open to discussing the topics I write about!

Recommended Reading

Creating and customizing a responsive navbar that adapts on mobile and desktop devices using Material UI (MUI) & React.

react
mui

Discussion

Upskill Your Frontend Development Techniques 🌟

Subscribe to stay up-to-date and receive quality front-end development tutorials straight to your inbox!

No spam, sales, or ads. Unsubscribe anytime you wish.

© 2024, Muhi Masri