Text Field
Text fields let users enter and edit text.
Text fields allow users to enter text into a UI. They typically appear in forms and dialogs.
Basic TextField
The TextField wrapper component is a complete form control including a label, input, and help text.
It comes with three variants: outlined (default), filled, and standard.
<TextField id="outlined-basic" label="Outlined" variant="outlined" />
<TextField id="filled-basic" label="Filled" variant="filled" />
<TextField id="standard-basic" label="Standard" variant="standard" />Note: The standard variant of the TextField is no longer documented in the Material Design guidelines
(here's why),
but MUI will continue to support it.
Form props
Standard form attributes are supported e.g. required, disabled, type, etc. as well as a helperText which is used to give context about a field's input, such as how the input will be used.
Validation
The error prop toggles the error state.
The helperText prop can then be used to provide feedback to the user about the error.
Multiline
The multiline prop transforms the text field into a <textarea> element.
Unless the rows prop is set, the height of the text field dynamically matches its content (using TextareaAutosize).
You can use the minRows and maxRows props to bound it.
Select
The select prop makes the text field use the Select component internally.
Input Adornments
The main way is with an InputAdornment.
This can be used to add a prefix, a suffix, or an action to an input.
For instance, you can use an icon button to hide or reveal the password.
kg
kg
Weight
$
kg
kg
Weight
$
kg
kg
Weight
$
The filled variant input height can be further reduced by rendering the label outside of it.
<TextField
hiddenLabel
id="filled-hidden-label-small"
defaultValue="Small"
variant="filled"
size="small"
/>
<TextField
hiddenLabel
id="filled-hidden-label-normal"
defaultValue="Normal"
variant="filled"
/>Margin
The margin prop can be used to alter the vertical spacing of the text field.
Using none (default) doesn't apply margins to the FormControl whereas dense and normal do.
<RedBar />
<TextField label={'margin="none"'} id="margin-none" />
<RedBar />
<TextField label={'margin="dense"'} id="margin-dense" margin="dense" />
<RedBar />
<TextField label={'margin="normal"'} id="margin-normal" margin="normal" />
<RedBar /><TextField fullWidth label="fullWidth" id="fullWidth" /><TextField
id="outlined-name"
label="Name"
value={name}
onChange={handleChange}
/>
<TextField
id="outlined-uncontrolled"
label="Uncontrolled"
defaultValue="foo"
/>Components
TextField is composed of smaller components (
FormControl,
Input,
FilledInput,
InputLabel,
OutlinedInput,
and FormHelperText
) that you can leverage directly to significantly customize your form inputs.
You might also have noticed that some native HTML input properties are missing from the TextField component.
This is on purpose.
The component takes care of the most used properties.
Then, it's up to the user to use the underlying component shown in the following demo. Still, you can use inputProps (and InputProps, InputLabelProps properties) if you want to avoid some boilerplate.
<Input defaultValue="Hello world" inputProps={ariaLabel} />
<Input placeholder="Placeholder" inputProps={ariaLabel} />
<Input disabled defaultValue="Disabled" inputProps={ariaLabel} />
<Input defaultValue="Error" error inputProps={ariaLabel} /><TextField label="Outlined secondary" color="secondary" focused />
<TextField label="Filled success" variant="filled" color="success" focused />
<TextField
label="Standard warning"
variant="standard"
color="warning"
focused
/>Customization
Here are some examples of customizing the component. You can learn more about this in the overrides documentation page.
Customization does not stop at CSS.
You can use composition to build custom components and give your app a unique feel.
Below is an example using the InputBase component, inspired by Google Maps.
🎨 If you are looking for inspiration, you can check MUI Treasury's customization examples.
useFormControl
For advanced customization use cases, a useFormControl() hook is exposed.
This hook returns the context value of the parent FormControl component.
API
import { useFormControl } from '@mui/material/FormControl';
Returns
value (object):
value.adornedStart(bool): Indicate whether the childInputorSelectcomponent has a start adornment.value.setAdornedStart(func): Setter function foradornedStartstate value.value.color(string): The theme color is being used, inherited fromFormControlcolorprop .value.disabled(bool): Indicate whether the component is being displayed in a disabled state, inherited fromFormControldisabledprop.value.error(bool): Indicate whether the component is being displayed in an error state, inherited fromFormControlerrorpropvalue.filled(bool): Indicate whether input is filledvalue.focused(bool): Indicate whether the component and its children are being displayed in a focused statevalue.fullWidth(bool): Indicate whether the component is taking up the full width of its container, inherited fromFormControlfullWidthpropvalue.hiddenLabel(bool): Indicate whether the label is being hidden, inherited fromFormControlhiddenLabelpropvalue.required(bool): Indicate whether the label is indicating that the input is required input, inherited from theFormControlrequiredpropvalue.size(string): The size of the component, inherited from theFormControlsizepropvalue.variant(string): The variant is being used by theFormControlcomponent and its children, inherited fromFormControlvariantpropvalue.onBlur(func): Should be called when the input is blurredvalue.onFocus(func): Should be called when the input is focusedvalue.onEmpty(func): Should be called when the input is emptiedvalue.onFilled(func): Should be called when the input is filled
Example
<FormControl sx={{ width: '25ch' }}>
<OutlinedInput placeholder="Please enter text" />
<MyFormHelperText />
</FormControl>Limitations
Shrink
The input label "shrink" state isn't always correct. The input label is supposed to shrink as soon as the input is displaying something. In some circumstances, we can't determine the "shrink" state (number input, datetime input, Stripe input). You might notice an overlap.

To workaround the issue, you can force the "shrink" state of the label.
<TextField InputLabelProps={{ shrink: true }} />
or
<InputLabel shrink>Count</InputLabel>
Floating label
The floating label is absolutely positioned. It won't impact the layout of the page. Make sure that the input is larger than the label to display correctly.
type="number"
Inputs of type="number" have potential usability issues:
- Allowing certain non-numeric characters ('e', '+', '-', '.') and silently discarding others
- The functionality of scrolling to increment/decrement the number can cause accidental and hard-to-notice changes
and more - see this article by the GOV.UK Design System team for a more detailed explanation.
For number validation, one viable alternative is to use the default input type="text" with the pattern attribute, for example:
<TextField inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }} />
In the future, we might provide a number input component.
Helper text
The helper text prop affects the height of the text field. If two text fields are placed side by side, one with a helper text and one without, they will have different heights. For example:
Please enter your name
<TextField
helperText="Please enter your name"
id="demo-helper-text-misaligned"
label="Name"
/>
<TextField id="demo-helper-text-misaligned-no-helper" label="Name" />This can be fixed by passing a space character to the helperText prop:
Please enter your name
<TextField
helperText="Please enter your name"
id="demo-helper-text-aligned"
label="Name"
/>
<TextField
helperText=" "
id="demo-helper-text-aligned-no-helper"
label="Name"
/>Integration with 3rd party input libraries
You can use third-party libraries to format an input.
You have to provide a custom implementation of the <input> element with the inputComponent property.
The following demo uses the react-imask and react-number-format libraries. The same concept could be applied to e.g. react-stripe-element.
The provided input component should expose a ref with a value that implements the following interface:
interface InputElement {
focus(): void;
value?: string;
}
const MyInputComponent = React.forwardRef((props, ref) => {
const { component: Component, ...other } = props;
// implement `InputElement` interface
React.useImperativeHandle(ref, () => ({
focus: () => {
// logic to focus the rendered component from 3rd party belongs here
},
// hiding the value e.g. react-stripe-elements
}));
// `Component` will be your `SomeThirdPartyComponent` from below
return <Component {...other} />;
});
// usage
<TextField
InputProps={{
inputComponent: MyInputComponent,
inputProps: {
component: SomeThirdPartyComponent,
},
}}
/>;
Accessibility
In order for the text field to be accessible, the input should be linked to the label and the helper text. The underlying DOM nodes should have this structure:
<div class="form-control">
<label for="my-input">Email address</label>
<input id="my-input" aria-describedby="my-helper-text" />
<span id="my-helper-text">We'll never share your email.</span>
</div>
- If you are using the
TextFieldcomponent, you just have to provide a uniqueid. - If you are composing the component:
<FormControl>
<InputLabel htmlFor="my-input">Email address</InputLabel>
<Input id="my-input" aria-describedby="my-helper-text" />
<FormHelperText id="my-helper-text">We'll never share your email.</FormHelperText>
</FormControl>
Complementary projects
For more advanced use cases, you might be able to take advantage of:
- react-hook-form: React hook for form validation.
- formik-material-ui: Bindings for using MUI with formik.
- redux-form-material-ui: Bindings for using MUI with Redux Form.
- mui-rff: Bindings for using MUI with React Final Form.
Unstyled
For advanced customization scenarios, you can use the unstyled primitives.
The basic building blocks are the InputUnstyled component and the useInput hook.
Unstyled component
The InputUnstyled component wraps the native input or textarea element.
You can, optionally, provide a custom component to be rendered instead.
<CustomInput aria-label="Demo input" placeholder="Type something..." />Hook
The useInput hook is the headless version of the InputUnstyled component.
Use it for even greater control over the rendered output.
<CustomInput aria-label="Demo input" placeholder="Type something..." />