MUI Components
NPM

Installation

@nish1896/mui-components grew out of @nish1896/rhf-mui-components. Its components proved useful enough that a standalone Material UI package — usable on its own or with any form library was the natural next step. It saves developers, junior and senior alike, significant time and effort in building consistent form UIs.

Setup

Install the package:

npm install @nish1896/mui-components
yarn add @nish1896/mui-components
pnpm add @nish1896/mui-components

The package expects Material UI v9 and its peers in your app.

npm install @mui/material @mui/icons-material @emotion/react @emotion/styled
yarn add @mui/material @mui/icons-material @emotion/react @emotion/styled
pnpm add @mui/material @mui/icons-material @emotion/react @emotion/styled

Date & time pickers additionally use MUI X (v9) and a date adapter of your choice, with AdapterDayjs being recommended by Material UI.

npm install @mui/x-date-pickers dayjs
yarn add @mui/x-date-pickers dayjs
pnpm add @mui/x-date-pickers dayjs

To minimize the bundle size during the build process, this package includes both named and default exports within each module. Similar to Material-UI, developers are encouraged to use default import syntax to reduce bundle size.

The type for each component can also be imported to modify or customize an existing component.

Quick start

Import components from their subpath and control them like any other input:

import { useState } from 'react';
import MUITextField from '@nish1896/mui-components/mui/textfield';

export default function SignupName() {
  const [firstName, setFirstName] = useState('');
  const [error, setError] = useState<string>();

  return (
    <MUITextField
      fieldName="firstName"
      value={firstName}
      onValueChange={({ newValue }) => setFirstName(newValue)}
      onBlur={() => setError(firstName ? undefined : 'First name is required')}
      required
      errorMessage={error}
    />
  );
}

There is no schema, resolver or registration step — derive errorMessage from your own validation (or your form library's) and the field renders in an error state.

Using rhf-mui-components?

Is this package similar to @nish1896/rhf-mui-components?

Yes. The component API is largely the same. The main difference is that control and registerOptions from rhf-mui-components have been replaced with the controlled value / onValueChange / errorMessage props.

The developer has to provide value and manage the validation on his end, rendering logic is managed within the component itself.

Starting with v4.2.0, @nish1896/rhf-mui-components now reuses the core logic and default values from this package.

Using Form Libraries

Because the components are controlled, adapting them to a form library takes only a few lines. errorMessage accepts a single message string, or a string[] when a field can fail several rules at once — so each library only needs a small adapter to map its own error shape onto that.

With TanStack Form's Field, whose meta.errors is an array that may nest, a one-line helper flattens it to a string[]:

import { useForm } from '@tanstack/react-form';
import MUITextField from '@nish1896/mui-components/mui/textfield';

/**
 * Flatten one level so a field failing several rules — where `meta.errors`
 * is `[[ruleA, ruleB]]` — surfaces every message.
 */
const tanstackErrors = (errors: unknown[]): string[] =>
  errors.flat().filter((error): error is string => typeof error === 'string');

const form = useForm({
  defaultValues: { email: '' }
});

<form.Field
  name="email"
  validators={{
    onChange: ({ value }) => (!value ? 'Email is required' : undefined)
  }}
>
  {field => (
    <MUITextField
      fieldName="email"
      value={field.state.value}
      onValueChange={({ newValue }) => field.handleChange(newValue)}
      onBlur={field.handleBlur}
      errorMessage={tanstackErrors(field.state.meta.errors)}
    />
  )}
</form.Field>

Overriding Default Config

Wrap your app in the ConfigProvider to set package-wide defaults — label placement, default sx for labels and helper text, and the date adapter used by the pickers:

import { ConfigProvider } from '@nish1896/mui-components/config';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';

<ConfigProvider
  allLabelsAboveFields
  dateAdapter={AdapterDayjs}
  defaultFormLabelSx={{ color: '#1976D2' }}
>
  <App />
</ConfigProvider>

Explore the Customization example for a complete working implementation.