{"id":21432078,"url":"https://github.com/lookfirst/mui-rff","last_synced_at":"2026-04-06T22:03:47.209Z","repository":{"id":38804949,"uuid":"215825089","full_name":"lookfirst/mui-rff","owner":"lookfirst","description":"MUI 5 / Material UI + React Final Form","archived":false,"fork":false,"pushed_at":"2025-05-12T16:06:45.000Z","size":43361,"stargazers_count":493,"open_issues_count":22,"forks_count":90,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-12T17:26:36.394Z","etag":null,"topics":["react","typescript"],"latest_commit_sha":null,"homepage":"https://lookfirst.github.io/mui-rff/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lookfirst.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-17T15:23:47.000Z","updated_at":"2025-05-12T16:15:28.000Z","dependencies_parsed_at":"2024-04-15T19:47:23.070Z","dependency_job_id":"2297a271-556d-4b3f-8af7-ef448142fda0","html_url":"https://github.com/lookfirst/mui-rff","commit_stats":{"total_commits":618,"total_committers":49,"mean_commits":"12.612244897959183","dds":0.2637540453074434,"last_synced_commit":"b4791939cc0c2bb65e79b11dab288bb7a13f4654"},"previous_names":[],"tags_count":128,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lookfirst%2Fmui-rff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lookfirst%2Fmui-rff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lookfirst%2Fmui-rff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lookfirst%2Fmui-rff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lookfirst","download_url":"https://codeload.github.com/lookfirst/mui-rff/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253788317,"owners_count":21964503,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","typescript"],"created_at":"2024-11-22T23:16:13.287Z","updated_at":"2026-04-06T22:03:47.198Z","avatar_url":"https://github.com/lookfirst.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![MUI-RFF, MUI and React Final Form](https://pimp-my-readme-next.vercel.app/api/wavy-banner?subtitle=MUI%20and%20React%20Final%20Form\u0026title=MUI-RFF)](https://pimp-my-readme-next.vercel.app)\n\n[![NPM Version](https://badgen.net/npm/v/mui-rff)](https://www.npmjs.com/package/mui-rff)\n[![NPM Downloads](https://badgen.net/npm/dm/mui-rff)](https://www.npmjs.com/package/mui-rff)\n[![min-zipped size](https://badgen.net/bundlephobia/minzip/mui-rff)](https://bundlephobia.com/result?p=mui-rff)\n[![Build status](https://github.com/lookfirst/mui-rff/workflows/Node%20CI/badge.svg)](https://github.com/lookfirst/mui-rff)\n[![CLA assistant](https://cla-assistant.io/readme/badge/lookfirst/mui-rff)](https://cla-assistant.io/lookfirst/mui-rff)\n\n**Welcome!** Thanks for stopping by and taking a look at this project. Let me briefly explain what it does.\n\nIn order to integrate [React Final Form](https://final-form.org/react) with a UI component library such as [Material UI](https://mui.com), you'll need to create a thin wrapper that passes properties between MUI and RFF components. After searching around for who else has done this, you've stumbled across this project.\n\nSadly, figuring out the nuances of passing properties across multiple components is non-trivial. It takes a lot of trial and error, and hopefully you're writing tests along the way too (hahaha yea, right). Since you are probably in a rush and just want to get onto building features, this repo provides a set of modern and unit tested React components that make it easy to drop into your own Javascript or Typescript project as a small NPM dependency.\n\nPlease try things out and review the code first. Take a look at the [demo](https://lookfirst.github.io/mui-rff/), [demo source](https://github.com/lookfirst/mui-rff/tree/master/example), [demo codesandbox](https://codesandbox.io/s/react-final-form-material-ui-example-xxspf), [another codesandbox](https://codesandbox.io/s/react-final-form-material-ui-example-tqv09), and the [tests](https://github.com/lookfirst/mui-rff/tree/master/test).\n\nOne thing to note in the [demo](https://lookfirst.github.io/mui-rff/) is the ability to control the React form rendering. This is what really motivated me to go with RFF. With a small [configuration tweak to RFF](https://final-form.org/docs/react-final-form/types/FormProps#subscription), it is easy to cut the number of renders down to the bare minimum. This improves performance significantly, especially with larger forms.\n\nI welcome issues to discuss things or even pr's!\n\n**If you like us, please ⭐ ⭐ star this project ⭐ ⭐**\n\n[![Star History Chart](https://api.star-history.com/svg?repos=lookfirst/mui-rff\u0026type=Date)](https://www.star-history.com/#lookfirst/mui-rff\u0026Date)\n\n# Usage\n\nv6.0+ of mui-rff depends on React 19.\n\nBeyond the normal react dependencies, you'll need:\n\n`bun add mui-rff @mui/material @mui/x-date-pickers final-form react-final-form`\n\nIf you use the date/time pickers, you'll need:\n\n`bun add @date-io/core @date-io/date-fns date-fns`\n\nIt is unfortunate that so many dependencies need to be installed right now. Pretty sure fixing this will require a lot of work to split everything into separate packages, which seems quite overkill for this project.\n\nI recommend using Yup for the form validation:\n\n`bun add yup`\n\n# Getting started\n\nMUI-RFF follows the recommended practices for both MUI and RFF. Build your `\u003cForm/\u003e` and then insert MUI-RFF components. The [hello world example](https://codesandbox.io/s/react-final-form-material-ui-example-tno64) looks like this:\n\n\u003e Note: This project now uses Bun. Install from https://bun.sh and run `bun install` before development.\n\n```tsx\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Form } from 'react-final-form';\nimport { TextField } from 'mui-rff';\n\ninterface FormData {\n\thello: string;\n}\n\ninterface MyFormProps {\n\tinitialValues: FormData;\n}\n\nfunction App() {\n\treturn \u003cMyForm initialValues={{ hello: 'hello world' }} /\u003e;\n}\n\nfunction MyForm(props: MyFormProps) {\n\tconst { initialValues } = props;\n\n\t// yes, this can even be async!\n\tasync function onSubmit(values: FormData) {\n\t\tconsole.log(values);\n\t}\n\n\t// yes, this can even be async!\n\tasync function validate(values: FormData) {\n\t\tif (!values.hello) {\n\t\t\treturn { hello: 'Saying hello is nice.' };\n\t\t}\n\t\treturn;\n\t}\n\n\treturn (\n\t\t\u003cForm\n\t\t\tonSubmit={onSubmit}\n\t\t\tinitialValues={initialValues}\n\t\t\tvalidate={validate}\n\t\t\trender={({ handleSubmit, values }) =\u003e (\n\t\t\t\t\u003cform onSubmit={handleSubmit} noValidate\u003e\n\t\t\t\t\t\u003cTextField label=\"Hello world\" name=\"hello\" required={true} /\u003e\n\t\t\t\t\t\u003cpre\u003e{JSON.stringify(values)}\u003c/pre\u003e\n\t\t\t\t\u003c/form\u003e\n\t\t\t)}\n\t\t/\u003e\n\t);\n}\n\nReactDOM.render(\u003cApp /\u003e, document.querySelector('#root'));\n```\n\nYou'll notice that rendering the component and error handling is all done for you without any additional code. Personally, I find this to be the holy grail of building forms because all the magic is wrapped up into a nice clean interface so that all you care about is providing data and submitting it.\n\nUsing MUI-RFF to generate a bunch of form fields is as easy as declaring all the fields and rendering them...\n\n```tsx\nconst formFields: JSX.Element[] = [\n\t\u003cTextField name=\"name\" label=\"Invoice name\" /\u003e,\n\t\u003cKeyboardDatePicker name=\"date\" label=\"Invoice date\" dateFunsUtils={DateFnsUtils} /\u003e,\n\t\u003cTextField name=\"purchaseOrder\" label=\"Purchase order\" /\u003e,\n\t\u003cTextField name=\"supplier\" label=\"Supplier\" /\u003e,\n\t\u003cTextField name=\"purchasePrice\" label=\"Purchase price\" /\u003e,\n\t\u003cTextField name=\"depreciationType\" label=\"Depreciation type\" /\u003e,\n\t\u003cKeyboardDatePicker name=\"depreciationStart\" label=\"Depreciation start\" dateFunsUtils={DateFnsUtils} /\u003e,\n\t\u003cTextField name=\"depreciationRate\" label=\"Depreciation rate\" /\u003e,\n];\n\n\u003cGrid container direction=\"column\" alignContent=\"stretch\"\u003e\n\t{formFields.map((item, idx) =\u003e (\n\t\t\u003cGrid item className={classes.maxWidth} key={idx}\u003e\n\t\t\t{item}\n\t\t\u003c/Grid\u003e\n\t))}\n\u003c/Grid\u003e;\n```\n\nSee below for more examples and details about how to use this library... if there is something missing or confusing, please ask in the issue tracker.\n\n# Keeping up to date\n\nI generally don't like to break backwards compatibility. There is a number of unit tests which will break if that happens. Expect that major versions will break it and minor/patch versions shouldn't break anything. I like to keep up to date with the latest 3rd party dependencies because in the JS/TS land, code tends to quickly rot. I find that it is easier to fix smaller things than to batch up into a lot of large changes.\n\nThe [commit history works as a great changelog](https://github.com/lookfirst/mui-rff/commits/master). Versions are tagged, so it is clear what commits go into each version and I release early/often so that it is easy to identify when issues crop up. I generally try to have descriptive enough commit messages so that things are clear.\n\n# Upgrades\n\n## From 1.x to 2.0\n\nVersion 2.0 removes the default margin around components as well as the default time/date formats. This means that MUI-RFF does not override any MUI defaults, and you now have to set them on your own. The reason for this change was to allow for better integration with the [MUI Theme system](https://material-ui.com/customization/theming/). It was a mistake for me to have originally done this, my apologies.\n\nThere is now a number of [tests](https://github.com/lookfirst/mui-rff/tree/master/test) which case for this and the [demo](https://lookfirst.github.io/mui-rff/) has been updated.\n\nTo get the equivalent margin behavior back, you'll need to add properties to your theme:\n\n```tsx\nconst theme = createMuiTheme({\n\tprops: {\n\t\tMuiTextField: {\n\t\t\tmargin: 'normal',\n\t\t},\n\t\tMuiFormControl: {\n\t\t\tmargin: 'normal',\n\t\t},\n\t},\n});\n```\n\nAlternatively, each component has their own way of specifying these settings. Either as `margin=\"normal\"` or `formFieldProps` or `textFieldProps` depending on the component needs.\n\nTo get the equivalent date/time formats back, you'll need to specify them as properties:\n\n```tsx\n\u003cDatePicker\n\tlabel=\"Test\"\n\tname=\"date\"\n\trequired={true}\n\tdateFunsUtils={DateFnsUtils}\n\tmargin=\"normal\"\n\tvariant=\"inline\"\n\tformat=\"yyyy-MM-dd\"\n/\u003e\n```\n\nI think based on all these instructions you can see why I tried to pick a default!\n\n## From 2.7.5 to 3.0\n\nYup made some backwards incompatible changes. This probably only affects people who depend on yup directly, but I wanted to make sure that people who depend on this library aren't surprised by this. There are no changes in this library except to support the Yup changes.\n\n## From 3.0 to 5.0\n\nThis release is compatible with MUI v5 and thus adopts the 5.x version. If you are still using Material UI v4.x, you should keep using an older version, although we do not expect us to maintain it any longer beyond user contributed PRs We have gone out of our way to maintain backwards compatibility in order to lessen the effects of upgrading. We continue to believe that maintaining API compatibility is important. However, there are a few changes that are beyond our control and will require consideration...\n\nThe default color for `Checkboxes`, `Radios` and `Select`s and `Switch`es changed from `secondary` to `primary` in MUI v5. Set `color={secondary}` if you do not want the color to change, and you haven't set a color before.\n\nThe default variant for `TextField`s changed from `standard` to `outlined` in MUI v5. Set `variant={standard}` if you want the variant to remain unchanged, and you have not set a variant before. This also affects `DatePicker`s, `DateTimePicker`s, `TimePicker`s and `Autocomplete`s, since they use `TextField`s internally.\n\n`KeyboardDatePicker`, `KeyboardDateTimePicker` and `KeyboardTimePicker` are deprecated aliases for `DatePicker`, `DateTimePicker` and `TimePicker` respectively. Please make sure to update your code as soon as possible. We will be removing them in a future point release version that we have not decided upon yet (5.1, 5.2, etc...).\n\n## From 5.0 to 5.2.0\n\nPreviously, we wrapped your Date/Time components in a `\u003cLocalizationProvider\u003e` [MUI documentation](https://mui.com/components/date-picker/#requirements). This had the unfortunate effect of blocking upstream declarations of the component. This was reported in issue #634 and is now fixed. The solution is to wrap all of your Date/Time components like this (but do it for all of them, not just one at a time):\n\n```tsx\n\u003cLocalizationProvider dateAdapter={AdapterDateFns}\u003e\n\t\u003cDatePicker label=\"Test\" name=\"date\" required={true} inputFormat=\"yyyy-MM-dd\" /\u003e\n\u003c/LocalizationProvider\u003e\n```\n\nYou might encounter this error if you do not do this:\n\n`Error: Can not find utils in context. It looks like you forgot to wrap your component in LocalizationProvider, or pass dateAdapter prop directly.`\n\n## From 5.2.0 to 5.3.0\n\nIn their infinite wisdom, [MUI decided to move the DatePickers to another project](https://mui.com/x/react-date-pickers/migration-lab/). So, I've migrated the imports. Since you import mui-rff and not MUI directly, this shouldn't have an effect on you, but I'm going to note it here in the upgrade log.\n\n## From 5.x to 6.0.0\n\n6.x introduces React 18. All the credit goes to @wadsworj for their excellent contribution!\n\nPreviously deprecated Keyboard\\* wrappers were removed. Please migrate to the DatePicker/DateTimePicker components.\n\nThe dependencies in package.json were updated and unit tests fixed.\n\nThere are no other API changes on our end of things.\n\n## From 6.x to 7.0.0\n\nThanks to @Kyraminol in #1082, we are now at the latest 1.x version of Yup. Make sure to update your dependencies.\n\n## From 7.x to 8.0.0\n\nThanks to @lukas-cc in #1170, we have now switched to MUI 6.x. It should be backwards compatible with 5.x, but we will version higher regardless.\n\n# Components\n\nAll the components should allow passing MUI configuration properties to them so that they can be easily customized. In the case of RFF and MUI components with deeply nested structures of multiple subcomponents, you can pass the properties in with special top level properties. This is very hard to document fully without making a mess, so please refer to the source code and demos for examples.\n\n```tsx\n\u003cTextField fieldProps={{ validation: myValidationFunction }} /\u003e\n\n\u003cSelect menuItemProps={{ disableGutters: true }} /\u003e\n\n\u003cDatePicker TextFieldProps={{ variant: 'standard' }} /\u003e\n```\n\n## TextField - [MUI Docs](https://material-ui.com/components/text-fields/)\n\n```tsx\nimport { TextField } from 'mui-rff';\n\n\u003cTextField label=\"Hello world\" name=\"hello\" required={true} /\u003e;\n```\n\n## Checkboxes - [MUI Docs](https://material-ui.com/components/checkboxes/)\n\nIf you have a single checkbox, it is rendered without the label (if no label is defined) and the value is boolean. Otherwise, you get an array of values. An example of this is the 'employed' field in the demo.\n\n```tsx\nimport { Checkboxes, CheckboxData } from 'mui-rff';\n\nconst checkboxData: CheckboxData[] = [\n\t{ label: 'Item 1', value: 'item1' },\n\t{ label: 'Item 2', value: 'item2' },\n];\n\n\u003cCheckboxes label=\"Check at least one...\" name=\"best\" required={true} data={checkboxData} /\u003e;\n```\n\n## Switches - [MUI Docs](https://material-ui.com/components/switches/)\n\nIf you have a single switch, it is rendered without the label (if no label is defined) and the value is boolean. Otherwise, you get an array of values. An example of this is the 'available' field in the demo.\n\n```tsx\nimport { Switches, SwitchData } from 'mui-rff';\n\n// submits a boolean\n\u003cSwitches label=\"Enable feature X\" name=\"feature-x\" required={true} data={{ label: 'Feature X', value: true }} /\u003e;\n\n// submits an array of values of the toggled switches\nconst switchData: SwitchData[] = [\n\t{ label: 'Item 1', value: 'item1' },\n\t{ label: 'Item 2', value: 'item2' },\n];\n\u003cSwitches label=\"Check at least one...\" name=\"best\" required={true} data={switchData} /\u003e;\n```\n\n## Radios - [MUI Docs](https://material-ui.com/components/radio-buttons/)\n\nThis example shows that you can inline the configuration data instead of passing it in like in the Checkboxes example above.\n\n```tsx\nimport { Radios } from 'mui-rff';\n\n\u003cRadios\n\tlabel=\"Pick one...\"\n\tname=\"gender\"\n\trequired={true}\n\tdata={[\n\t\t{ label: 'Item 1', value: 'item1' },\n\t\t{ label: 'Item 2', value: 'item2' },\n\t]}\n/\u003e;\n```\n\n## Select - [MUI Docs](https://material-ui.com/components/selects/)\n\nSelect allows you to inline the MUI `\u003cMenuItem\u003e` component. You can also pass in a `data=` property similar to Checkboxes and Radios and the items will be generated for you. This example shows overriding the MUI default `formControl` properties.\n\n```tsx\nimport { Select } from 'mui-rff';\nimport { MenuItem } from '@material-ui/core';\n\n\u003cSelect name=\"city\" label=\"Select a City\" formControlProps={{ margin: 'normal' }}\u003e\n\t\u003cMenuItem value=\"London\"\u003eLondon\u003c/MenuItem\u003e\n\t\u003cMenuItem value=\"Paris\"\u003eParis\u003c/MenuItem\u003e\n\t\u003cMenuItem value=\"Budapest\"\u003eA city with a very long Name\u003c/MenuItem\u003e\n\u003c/Select\u003e;\n```\n\n## DatePicker - [MUI Docs](https://mui.com/x/react-date-pickers/date-picker/)\n\nYou'll need to add dependencies:\n\n`bun add @mui/x-date-pickers @date-io/core @date-io/date-fns date-fns`\n\n```tsx\nimport { DatePicker } from 'mui-rff';\n\nimport 'date-fns';\nimport DateFnsUtils from '@date-io/date-fns';\n\n\u003cDatePicker label=\"Pick a date\" name=\"date\" required={true} /\u003e;\n```\n\n## TimePicker - [MUI Docs](https://mui.com/x/react-date-pickers/time-picker/)\n\nYou'll need to add dependencies:\n\n`bun add @mui/x-date-pickers @date-io/core @date-io/date-fns date-fns`\n\n```tsx\nimport { TimePicker } from 'mui-rff';\n\nimport 'date-fns';\nimport DateFnsUtils from '@date-io/date-fns';\n\n\u003cTimePicker label=\"Pick a date\" name=\"date\" required={true} /\u003e;\n```\n\n## DateTimePicker - [MUI Docs](https://mui.com/x/react-date-pickers/date-time-picker/)\n\nYou'll need to add dependencies:\n\n`bun add @mui/x-date-pickers @date-io/core @date-io/date-fns date-fns`\n\n```tsx\nimport { DateTimePicker } from 'mui-rff';\n\nimport 'date-fns';\nimport DateFnsUtils from '@date-io/date-fns';\n\n\u003cDateTimePicker label=\"Pick a date and time\" name=\"datTtime\" required={true} /\u003e;\n```\n\n## Autocomplete - [MUI Docs](https://material-ui.com/components/autocomplete/)\n\n\u003e Note: Part of the @material-ui/lab dependency.\n\n```tsx\nimport React from 'react';\nimport { Checkbox as MuiCheckbox } from '@material-ui/core';\nimport { Autocomplete } from 'mui-rff';\n\nconst autocompleteData = [\n\t{ label: 'Earth', value: 'earth' },\n\t{ label: 'Mars', value: 'mars' },\n\t{ label: 'Venus', value: 'venus' },\n\t{ label: 'Brown Dwarf Glese 229B', value: '229B' },\n];\n\n\u003cAutocomplete\n\tlabel=\"Pick at least one planet\"\n\tname=\"planet\"\n\trequired={true}\n\toptions={autocompleteData}\n\tgetOptionValue={(option) =\u003e option.value}\n\tgetOptionLabel={(option) =\u003e option.label}\n\tdisableCloseOnSelect={true}\n\trenderOption={(option, { selected }) =\u003e (\n\t\t\u003c\u003e\n\t\t\t\u003cMuiCheckbox style={{ marginRight: 8 }} checked={selected} /\u003e\n\t\t\t{option.label}\n\t\t\u003c/\u003e\n\t)}\n\tmultiple\n/\u003e;\n```\n\nWhen `multiple` is `true`, the `initialValues` passed into the `\u003cForm\u003e` element needs to be an array...\n\n```tsx\nconst initialValues: { planet: string[] } = {\n\tplanet: ['mars'], // \u003c-- Needs to be an array\n};\n\n\u003cForm\n\tinitialValues={initialValues}\n\trender={({ handleSubmit }) =\u003e (\n\t\t\u003cform onSubmit={handleSubmit}\u003e\n\t\t\t\u003cAutocomplete label=\"Pick at least one planet\" name=\"planet\" multiple /\u003e\n\t\t\u003c/form\u003e\n\t)}\n/\u003e;\n```\n\n# Helpers\n\nOptional helpers to make dealing with form validation a breeze!\n\n## makeValidate(schema)\n\nForm validation is a notorious pain in the arse and there are a couple libraries out there to help simplify things. After experimenting with both [Yup](https://github.com/jquense/yup) and Joi, I've settled on Yup. The main reason is that for form validation, Yup has the ability to validate all the schema and Joi stops on the first failure. Joi is also originally focused on server side validation, while Yup focuses on running in the browser.\n\nThat said, it is still helpful to translate Yup errors into something that Final Form can deal with. Final Form expects validation to return an object where the key is the field name and the value is the error message. This little helper does what we need:\n\n`bun add yup @types/yup`\n\n```tsx\nimport { Form } from 'react-final-form';\nimport { makeValidate } from 'mui-rff';\nimport * as Yup from 'yup';\n\n// We define our schema based on the same keys as our form:\nconst schema = Yup.object().shape({\n\temployed: Yup.boolean().required(),\n});\n\n// Run the makeValidate function...\nconst validate = makeValidate(schema);\n\n// Then pass the result into the \u003cForm/\u003e...\n\u003cForm validate={validate}\u003e\n\t\u003cCheckboxes name=\"employed\" required={true} data={{ label: 'Employed', value: true }} /\u003e\n\u003c/Form\u003e;\n```\n\n## makeValidate(schema, translator?)\n\nYup [can be configured](https://github.com/jquense/yup#using-a-custom-locale-dictionary) to have a custom locale for when you need to translate your error messages or just general need more control. `makeValidate` accepts a second argument which is a `translator` which can return a `string` or a `JSX.Element`. So it can also be used if you have multiple errors and want to display them nicely via css (or e.g. hide the second)\n\n```tsx\nimport { Form } from 'react-final-form';\nimport { makeValidate } from 'mui-rff';\nimport * as Yup from 'yup';\n\nimport t from 'some-kind-of-internationalization-library-like-i18next';\n\n// setup your locale and pass whatever your translator could use\nYup.setLocale({\n\tmixed: {\n\t\trequired: (props) =\u003e ({\n\t\t\tkey: 'field_required',\n\t\t\t...props,\n\t\t}),\n\t},\n});\n\n// We define our schema based on the same keys as our form:\nconst schema = Yup.object().shape({\n\temployed: Yup.boolean().required(),\n});\n\n// Run the makeValidate function...\nconst validate = makeValidate(schema, (error) =\u003e {\n\tconst { field, ...rest } = error;\n\treturn \u003cspan className=\"error\"\u003e{t(`errors:${error.field}`, rest)}\u003c/span\u003e;\n});\n```\n\n## makeValidateSync(schema, translator?)\n\nSame as `makeValidate` but synchronous.\n\n## makeRequired(schema)\n\nExpanding on the example above, we can see that the `employed` checkbox is required in the schema, but we still need to define the `\u003cCheckboxes...` `required={true}` property, this is ugly because the two can get out of sync.\n\nWe can then use another helper function to parse the schema and return an object where the key is the field name and the value is a boolean.\n\n`bun add yup @types/yup`\n\n```tsx\nimport { Form } from 'react-final-form';\nimport { Checkboxes, makeValidate } from 'mui-rff';\nimport * as Yup from 'yup';\n\n// We define our schema based on the same keys as our form:\nconst schema = Yup.object().shape({\n\temployed: Yup.boolean().required(),\n});\n\nconst validate = makeValidate(schema);\n\n// Adding in the additional schema parsing...\nconst required = makeRequired(schema);\n\n// Then pass it into the \u003cForm/\u003e\n\u003cForm validate={validate}\u003e\n\t\u003cCheckboxes name=\"employed\" required={required.employed} data={{ label: 'Employed', value: true }} /\u003e\n\u003c/Form\u003e;\n```\n\n# Validation Types\n\nEvery field we export will take a `showError` prop which is a function, which returns a boolean, that is used to determine how and when to show error messages, by using `meta` props from the FinalForm field state.\n\nThese are the two available pre-defined options exported from within this library (defined in src/Util.tsx):\n\n## showErrorOnChange({ meta }) - default\n\nTriggers error messages to show up as soon as a value of a field changes. Useful for when the user needs instant feedback from the form validation (i.e. password creation rules, non-text based inputs like select, or switches etc.)\n\n## showErrorOnBlur({ meta })\n\nTriggers error messages to render after a field is touched, and blurred (focused out of), this is useful for text fields which might start out erroneous but end up valid in the end (i.e. email, or zipcode). In these cases you don't want to rush to show the user a validation error message when they haven't had a chance to finish their entry.\n\n```tsx\nimport { TextField, showErrorOnBlur } from 'mui-rff';\n\n\u003cTextField label=\"Hello world\" name=\"hello\" required={true} showError={showErrorOnBlur} /\u003e;\n```\n\n## You can also make your own override:\n\n```tsx\nimport { TextField } from 'mui-rff';\n\n// define your own showError-type function\nfunction myShowErrorFunction({ meta: { submitError, dirtySinceLastSubmit, error, touched, modified } }) {\n\t// this is actually the contents of showErrorOnBlur but you can be as creative as you want.\n\treturn !!(((submitError \u0026\u0026 !dirtySinceLastSubmit) || error) \u0026\u0026 touched);\n}\n\n\u003cTextField label=\"Hello world\" name=\"hello\" required={true} showError={myShowErrorFunction} /\u003e;\n```\n\n## Debug\n\nPrints out the JSON version of the form data.\n\n```tsx\nimport { Checkboxes, Debug } from 'mui-rff';\n\n\u003cForm\u003e\n\t\u003cCheckboxes name=\"employed\" data={{ label: 'Employed', value: true }} /\u003e\n\t\u003cDebug /\u003e\n\u003c/Form\u003e;\n```\n\n# Building\n\nThis project uses [Bun](https://bun.sh/) for local development.\n\n- Clone the project.\n- `bun install` to install dependencies (root + example workspace)\n- `bun run build` to build the distribution\n- push to `master` to run CI; releases are cut by GitHub Actions\n- `bun run test` to run the test suite\n- `bun run lint` and `bun run lint-fix` to auto format code\n- `cd example \u0026\u0026 bun install \u0026\u0026 bun run dev` to run the example on http://localhost:3000\n\nRelease automation uses commit messages to determine the version bump:\n\n- breaking changes (`feat!:` / `fix!:` / `BREAKING CHANGE:`) trigger a major release\n- `feat:` triggers a minor release\n- everything else defaults to a patch release\n\nTo do development, I do a mix of TDD and running the example application. Run `bun run start` in the top level directory for library development with watch mode, and `bun run dev` in the example folder for the demo application.\n\n---\n\n### Credits\n\nThanks to the awesome work by these projects:\n\n- React\n- Material-UI\n- React Final Form\n- Vitest\n- React Testing Library\n- Vite\n- Typescript\n- Bun\n- And all their dependencies...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flookfirst%2Fmui-rff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flookfirst%2Fmui-rff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flookfirst%2Fmui-rff/lists"}