Welcome. Thanks for taking a look at the project.
mui-rff provides thin, tested wrapper components that connect MUI with React Final Form. It removes the repetitive glue code needed to wire form state, validation, and error display into common MUI inputs, so you can focus on building forms instead of bridging two libraries.
This project is 7+ years old now and still actively supported. A large suite of unit tests makes that practical by catching compatibility issues early as React, MUI, Final Form, and related dependencies evolve.
It also has an automated CI and release pipeline, so dependency updates and releases are validated consistently instead of relying on manual steps.
If you enjoy this project, consider giving it a star. We could use the support.
Demo · Example source · Tests · CI setup · npm
Current releases target:
- React 19
react-final-form7final-form5@mui/material9@mui/x-date-pickers9
See package.json for the authoritative peer dependency ranges.
Install the package and its peer dependencies:
bun add mui-rff @emotion/react @emotion/styled @mui/material @mui/system @mui/x-date-pickers final-form react react-final-formIf you use date pickers, also install a date adapter:
bun add @date-io/core @date-io/date-fns date-fnsIf you use Yup-based validation helpers:
bun add yupBuild your <Form /> with React Final Form, then render mui-rff fields inside it.
import { Form } from 'react-final-form';
import { TextField } from 'mui-rff';
interface FormData {
hello: string;
}
export function MyForm() {
async function onSubmit(values: FormData) {
console.log(values);
}
function validate(values: FormData) {
if (!values.hello) {
return { hello: 'Saying hello is nice.' };
}
return undefined;
}
return (
<Form<FormData>
initialValues={{ hello: 'hello world' }}
onSubmit={onSubmit}
validate={validate}
render={({ handleSubmit, values }) => (
<form onSubmit={handleSubmit} noValidate>
<TextField label="Hello world" name="hello" required />
<pre>{JSON.stringify(values, null, 2)}</pre>
</form>
)}
/>
);
}Wrap picker components in MUI's LocalizationProvider:
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DatePicker } from 'mui-rff';
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker label="Invoice date" name="date" />
</LocalizationProvider>;The package exports wrappers for the most common MUI form inputs:
AutocompleteCheckboxesDatePickerDateTimePickerRadiosSelectSwitchesTextFieldTimePickerDebug
It also exports validation and error utilities:
makeRequiredmakeValidatemakeValidateSyncErrorMessageshowErrorOnBlurshowErrorOnChangeuseFieldForErrors
These examples are intentionally small. For more complete patterns, check the demo app and tests.
import { TextField } from 'mui-rff';
<TextField label="Hello world" name="hello" required />;import { Checkboxes } from 'mui-rff';
<Checkboxes
label="Check at least one"
name="best"
required
data={[
{ label: 'Item 1', value: 'item1' },
{ label: 'Item 2', value: 'item2' },
]}
/>;import { Switches } from 'mui-rff';
<Switches label="Enable feature X" name="featureX" data={{ label: 'Feature X', value: true }} />;import { Radios } from 'mui-rff';
<Radios
label="Pick one"
name="choice"
required
data={[
{ label: 'Item 1', value: 'item1' },
{ label: 'Item 2', value: 'item2' },
]}
/>;import MenuItem from '@mui/material/MenuItem';
import { Select } from 'mui-rff';
<Select label="Select a city" name="city">
<MenuItem value="London">London</MenuItem>
<MenuItem value="Paris">Paris</MenuItem>
<MenuItem value="Budapest">Budapest</MenuItem>
</Select>;import { DatePicker } from 'mui-rff';
<DatePicker label="Pick a date" name="date" required />;import { TimePicker } from 'mui-rff';
<TimePicker label="Pick a time" name="time" required />;import { DateTimePicker } from 'mui-rff';
<DateTimePicker label="Pick a date and time" name="dateTime" required />;import Checkbox from '@mui/material/Checkbox';
import { Autocomplete } from 'mui-rff';
const planetOptions = [
{ label: 'Earth', value: 'earth' },
{ label: 'Mars', value: 'mars' },
{ label: 'Venus', value: 'venus' },
];
<Autocomplete
label="Pick planets"
name="planet"
options={planetOptions}
getOptionLabel={(option) => option.label}
getOptionValue={(option) => option.value}
disableCloseOnSelect
multiple
renderOption={(props, option, { selected }) => (
<li {...props}>
<Checkbox checked={selected} sx={{ mr: 1 }} />
{option.label}
</li>
)}
/>;When multiple is enabled, the corresponding initialValues entry should be an array:
import { Form } from 'react-final-form';
<Form initialValues={{ planet: ['mars'] }}>{/* ... */}</Form>import { Debug } from 'mui-rff';
<Debug />;Each wrapper accepts the usual MUI props plus component-specific pass-through props for nested elements. For example:
<TextField fieldProps={{ validate: myValidationFunction }} />
<Select menuItemProps={{ disableGutters: true }} />
<DatePicker TextFieldProps={{ variant: 'outlined' }} />Refer to the source and example app for complete usage patterns.
Validation helpers are available if you use Yup schemas:
import { TextField, makeRequired, makeValidate, showErrorOnBlur } from 'mui-rff';
import * as Yup from 'yup';
const schema = Yup.object({
email: Yup.string().email().required(),
});
const validate = makeValidate(schema);
const required = makeRequired(schema);
<TextField
label="Email"
name="email"
required={required.email}
showError={showErrorOnBlur}
/>;This repository uses Bun for local development.
Long-term maintenance depends heavily on the test suite. The project has stayed healthy across multiple major dependency upgrades because the unit tests provide a reliable compatibility safety net.
The repository also uses automated GitHub Actions for pull request validation, versioning, releases, GitHub Pages deployment, and npm publishing. See CI.md for the full setup.
If you want to build a similar pipeline for your own project, CI.md is meant to be practical reference material: you can treat it as a reusable playbook, or even as a skill prompt, for setting up a modern CI workflow with protected branches, automated releases, and trusted publishing.
bun install
bun run ciUseful scripts:
bun run buildbun run testbun run lintbun run tsc
5.2.0+: Date and time pickers must be wrapped inLocalizationProvider.6.0.0: DeprecatedKeyboard*picker aliases were removed.7.0.0: Yup support was updated to the 1.x line.8.0.0: The package moved to MUI 6 and remains broadly compatible with MUI 5-style usage where upstream APIs allow it.9.0.0: Breaking. Requires MUI v9 and@mui/x-date-pickersv9. MUI v7/v8 are no longer supported. If your app uses deprecated MUI v7 props onTextField(InputProps,inputProps,InputLabelProps,FormHelperTextProps,SelectProps), migrate them toslotPropsbefore upgrading — see the MUI v9 migration guide. TheAutocompletecomponent's v7 backward-compat shim has been removed; pass adornments and input customizations viatextFieldProps.slotProps.inputinstead oftextFieldProps.InputProps.
For project history, see the commit log and GitHub releases.
Issues and pull requests are welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.