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-componentsyarn add @nish1896/mui-componentspnpm add @nish1896/mui-componentsThe package expects Material UI v9 and its peers in your app.
npm install @mui/material @mui/icons-material @emotion/react @emotion/styledyarn add @mui/material @mui/icons-material @emotion/react @emotion/styledpnpm add @mui/material @mui/icons-material @emotion/react @emotion/styledDate & 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 dayjsyarn add @mui/x-date-pickers dayjspnpm add @mui/x-date-pickers dayjsTo 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.
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.