Skip to main content
Form - Demos


This package exposes a few components to help render accessible forms:

  • Checkbox
  • Radio
  • InputToggle
  • Switch
  • AsyncSwitch
  • FileInput
  • TextField
  • TextArea
  • Password
  • NativeSelect
  • Label
  • Form
  • Fieldset

There are also some hooks available for controlling the state of these components:

  • useChecked
  • useChoice

Text Field Example

Text fields are a wrapper for the <input type="text" /> with some general themes and styles applied. There are four different themes available by default:

  • "unstyled" - removes all the default borders, background colors, etc.
  • "underline" - adds an underline to the text field that animates in when the input gains focus as well as including a floating label
  • "filled" - an extension of the "underline" theme that also adds a background color to it
  • "outline" - adds a outline to the text field and animates a floating label with it.
Text field theme
Text field options
Underline Directionleft

Text Field Types

The TextField component also has some limited support for rendering as other text input tyes:

  • password
  • number
  • tel
  • email
  • date
  • time
  • datetime-local
  • month
  • week
  • url

When you set the type prop to one of these values, no additional functionality or validation will be built in. The only support out of the box is to be styled correctly with some of the different types.

The "password" type is sort of an exception for this as there is a helper component: Password that allows the user to conditionally show the password in plain text.

Text field theme

Text Area Example

The TextArea component is a general wrapper for the <textarea> element with most of the same styles as the TextField. The TextArea will default to have a minimal starting height and animates as the user types. This behavior can be updated so that the transition for height changes is disabled and happens immediately. The default behavior is to allow the textarea to infinitely grow, but specific limits can be set by using the maxRows prop. The textarea will grow until the row limit and then allow native scrolling behavior within the textarea.

If this behavior is undesired, the resize prop can be changed to allow the user to manually resize instead with one of:

  • horizontal
  • vertical
  • both (native behavior)

Note: When the resize prop is set to "horizontal" or "both", the TextArea will be forced to render inline so that it can be resized horizontally.

Text field theme
Text field options
Underline Directionleft
Textarea options

File Input Example

A file input is just a simple wrapper of the <input type="file" /> that adds some default styles to look like a button. This means that all the themes available for a button are also available for this component. The file input has some reasonable defaults by showing a download file icon and a screen reader only accessible label of Upload. Unlike buttons, the file input is defaulted to render as an icon button with the primary theme color and the contained styles.

To use this component, you must provide:

  • an id for accessibility and making the button clickable
  • an onChange event handler
Last selected file:
Theme type

Native Select Example

The NativeSelect component is a simple wrapper for the <select> element with TextField styles. Just like native <select> elements, this wrapper does not support:

  • placeholder text
  • enabling readOnly (it can almost manually be done by disabiling each option yourself, but it'll make it impossible to close on mobile devices if it there are so many options that it covers the entire viewport)

That being said, the demo below will show you some patterns you can use to fake placeholder text using the floating label and an empty <option> element as well as a read-only view by disabling all <option>s.

Text field theme
Text field options
Underline Directionleft
Select options

Select Example

The Select component is a custom widget that allows you to have additional styling controls for a native <select> element while still being accessible. This component inherits all the TextField styles just like the NativeSelect, but also allows each option to be rendered like a ListItem from the @react-md/list and @react-md/menu packages.

Note: Even though the Select component supports the inline prop, it does not behave the same was as the NativeSelect or a native <select> component since it will not automatically update it's width to be the longest renderable option. The size will update whenever the value of the select changes.

This component is fully controlled, so you will need to provide the current value, an onChange handler, and a list of options. An option can be:

  • a number
  • a string
  • or an object of props to pass to a ListItem (see the next example for more details here)

The onChange handler will not be a native change event since there are no <input> or <select> elements being rendered. Instead, the onChange handler will be provided the next value string as the first argument and the option as the second: onChange(nextValue: string, option: object | string | number).

Just like a native <select> component, the list of options can be shown by clicking, pressing the space key, or using the up and down arrow keys. Once the list of options are shown, the user can:

  • type letters to find a match starting with the same letters
  • use the up and down arrow keys to focus the previous and next items
  • use the home and end keys to focus the first and last items
  • press the escape key to close the listbox
  • use the space or enter key to select and close the listbox

Check out the next example for some better examples of the typeahead feature

Text field theme
Text field options
Underline Directionleft
Select options

Customizing Select Options

The default behavior for the Select component is to just render any number or string options as the children within the ListItem. Since it is sometimes helpful to be able to add additional information, styling, or icons with the options, an option can also be an object of props to pass to the ListItem instead.

When the option is an object, the default behavior will be to:

  • use option.label || option.children as the displayable children
  • use the option.value as the value for this option
  • remove the option.label and option.value keys from the object before passing it as props to the ListItem

The label will be displayed in the option itself as well as in the select button when the option's value matches the select's value. This simplest way to add customization is to transform your list of options to follow this pattern.

However, this might not match all use-cases and customizations required, so the select also has the following props to help with rendering and accessibility:

  • labelKey - A key on the object that should be considered the label
  • valueKey - A key on the object that should be considered the value
  • getOptionLabel - A function that is called for each option to extract a label
  • getOptionValue - A function that is called for each option to extract a value
  • getDisplayLabel - A function that is called for the selected option that should return a renderable ode to display within the Select's button.

You probably won't need all this additional functionality other than the labelKey and valueKey props, but it might be useful for virtualization libraries or other stuff like that.

The examples below will show some use-cases for these props to add some more style to your select fields:

  • using the labelKey and valueKey props converting a list of states that have the format of interface State { name: string; abbreviation: string; } without needing to transform the list yourself
  • rendering custom children within each option and still being search accessible
  • displaying icons/avatars along with the selected option in the Select's button
Using Keys
Custom Children
StateFrozen yogurt (159 kcal)
Icons and Avatars

Checkbox and Radio Examples

Checkboxes and radios have been implemented to behave exactly like their native counterparts and add a slight animation when the selection state changes. Unlike v1 of react-md, all checkboxes and radios can be fully uncontrolled and will also reset correctly if a form reset button is clicked.

Checkboxes and radios can be created by either using the Checkbox and Radio components or the InputToggle component. The Checkbox and Radio components are just simple wrappers that will provide the correct type attribute and a reasonable default icon to use (a material icon for the checkbox/radio as an outline).

Indeterminate Checkboxes

The Checkbox component also supports an indeterminate state to help indicate that it controls the checked state for other checkboxes as well. To use this feature:

  • enable the indeterminate prop when all the checkboxes are not checked
  • set the aria-checked="mixed" when at least one checkbox is checked but not all
  • provide a space-delimited string of all the checkboxes it controls as the aria-controls attribute

The aria-controls part is a bit iffy since it might not actually do anything for screen readers and Lighthouse might also flag it as an invalid aria- attribute.

Sandwich Condiments

Custom Checkboxes

The Checkbox and Radio components use a little css trick with the ::before and ::after pseudo elements to animate the toggled states based on the :checked state. It is does this way so that each checkbox and radio can act like a native toggle input and not be fully controlled to swap out icons.

Unfortunately, this makes it a bit more difficult if you want to use custom icons that don't line up with the existing material icons' checkbox and radio outlines. When this happens, you'll want to use a new prop: disableIconOverlay to disable this behavior and implement your own icon swapping instead by either:

  • handling icon swaps all in CSS
  • make your checkboxes fully controlled
  • make your entire radio group fully controlled

You can also increase or decrease the size of the checkbox and radio components by updating the used CSS Variables for the toggle. Just add a custom class name and use the following mixins:

  • @include rmd-button-theme-update-var(icon-size, NEW_SIZE)
  • @include rmd-icon-theme-update-var(size, NEW_SIZE)
  • @include rmd-form-theme-update-var(icon-size, NEW_SIZE)

Switch Examples

A switch is another version of the Checkbox component that allows the user to toggle between distinct on and off states. Just like a checkbox, the switch can be toggled with a spacebar press and trigger a form submit when the enter key is pressed.

Async Switch Example

You can also use the AsyncSwitch component that will update the behavior of the Switch. When the loading prop is enabled, the Switch will gain a circular progress indicator and prevent the switch from being toggled again until the loading prop is set to false . This sort of switch is useful if you are trying to send an API request to update some behavior, but it fails due to some error.

Simple Help and Error Messages

The form package also exports a FormMessage component to add custom help text, error text, and a counter to a form elements but generally used alongside TextField components. The FormMessage component is mostly an accessibility helper that will ensure that help text and/or error text will be correctly read to screen readers if the contents change.

All that is required for this component is an id and matching the theme prop for the TextField component to get correct styling behavior. The example below will showcase a few simple examples.

Help Text

Error Text

0 / 20

Max 20 characters

0 / 20

Text Field Hook Examples

Form validation is pretty difficult and there's a lot of parts involved. If you looked over the Simple Help and Error Messages example you can see that it still isn't entirely "simple".

Note: You should check out the With React Hook Form example if you want to build truly complex forms instead of this example.

Starting with @react-md/form@2.5.0, there are a few new helper components to simplify this process as well as a new useTextField hook to control the value for text-like components. Here's a list of components to use:

  • TextFieldWithMessage instead of TextField
  • TextAreaWithMessage instead of TextArea
  • PasswordWithMessage instead of Password

Check out the example below to see some of the default behavior and how to create a form with some validation.


0 / 200
0 / 50

Create a password with at least 10 characters.

Number Hook Examples

Since the <input type="number"> behaves oddly, ReactMD exports a hook to deal with number fields named: useNumberField. This uses the useTextField internally to validate the number and return a valid number.

What this hook implements/fixes:

  • gets the current number from the text field

    • the number will only be undefined if the defaultValue option is undefined
    • the default will update as the user types, but can be configured to only update once the text field has been blurred with updateOnChange: false
  • shows an error if the user types an invalid number since the browser actually allows these sorts of inputs to be typed:

    • --0
    • 0-0
    • 0-0-
    • any of the above but with a + instead of a -
  • attempts to update the field on blur by:

    • setting the field value to the stringified number. Examples:
      • 000000 -> 0
      • 001 -> 1
    • fixing the value to be within the min and max values
    • all of the blur behavior can be configured or disabled by the fixOnBlur option

    Check out the examples below to see how this hook works.

value1: undefined

value2: undefined

value3: 0

value4: 0

value5: 0

Simple Sliders

A Slider is a component that allows the user to select a number value from a specific range of numbers. This component is fully controlled and requires the use of the useSlider hook to provide the value and "controls" to updating the value. The hook allows for customizing the min, max, and step options.

The Slider also requires a baseId and either a label, an aria-label, or an aria-labelledby for accessibility.

Check out the examples below to see how to use the useSlider hook and a few of the styling props available for the Slider.

Vertical Slider
Vertical Slider
Disabled Vertical Slider

Range Sliders

A RangeSlider is another implementation of a slider that allows the user to select a min and max value from a specific range of numbers. Like the Slider, this component is fully controlled and requires the use of the useRangeSlider hook to provide the value and "controls" to updating the value. The hook allows for customizing the min, max, and step options.

The RangeSlider also requires providing accessible labels for each "thumb" by one of the available label props:

  • thumb1Label - defaults to "Min"
  • thumb1LabelledBy
  • thumb2Label - defaults to "Max"
  • thumb2LabelledBy

Check out the examples below to see how to use the useRangeSlider hook and a few of the styling props available for the RangeSlider.


Color Dialog Slider

As mentioned above, the useSlider provides an object of controls as the second argument which is required to update the slider's value. The controls include the following functions:

  • increment - increment the value by the current step amount unless already at the max value
  • decrement - decrement the value by the current step amount unless already at the min value
  • minimum - set the value to the min amount
  • maximum - set the value to the max amount
  • setValue - a React "set state dispatcher" which can be used to set the value of the slider manually

This example will show how you can use the controls provided by the useSlider to link a TextField to the Slider and render it inline.

Discrete Sliders

The Slider and RangeSlider also support rendering a tooltip of the current value while the user is dragging or focusing the slider thumb. This can be enabled with the discrete prop.


Configurable Slider

The useSlider (and useRangeSlider) support an updateOn option that can be used to make the slider's value only update once the user has blurred the slider's thumb or completed dragging. This is useful when you don't need to use the value immediately and can be activated by setting updateOn: "blur".

There is also an onChange callback that can be used along with this updated behavior if desired.

This example allows you to configure some of the different props for the Slider component and showcasing the updateOn behavior.

Update Onchange

This is the distance the slider jumps when the PageUp or PageDown keys are pressed. Defaults to 1/10th of the slider's range.

Current value: 0


Example Form

This package also exports an extremely simple Form component that just prevents default behavior when it is submitted. This is super nice since the majority of the time you'll want to use ajax on form submit instead of the default behavior. Check out the example below for an extended usage of the Form component and some of the other components together to make a "New Contact" form.

Theme options
Full Address

With React Hook Form

react-md does not come with any form validation so you'll want to choose your favorite form library instead. This example will show how you can use react-hook-form along with react-md to create a simple form with error states, some validation, and the ability to reset the form.

Are you a developer?