Summary
The TextField / OutlinedInput / Input components have several spacing values written as literal numbers inside their styled() definitions, rather than being exposed as theme tokens. The same is true of InputLabel, whose transform: translate(x, y) values are implicitly coupled to the input's padding but are themselves hardcoded in a separate file.
In OutlinedInput.js the relevant literals include:
paddingLeft: 14 (when startAdornment is present)
paddingRight: 14 (when endAdornment is present)
padding: '16.5px 14px' (multiline, default)
padding: '8.5px 14px' (multiline, size="small")
padding: '16.5px 14px' / padding: '8.5px 14px' on OutlinedInputInput
In InputLabel.js the matching label positions are also literal:
transform: 'translate(14px, 16px) scale(1)' (outlined, default)
transform: 'translate(14px, 9px) scale(1)' (outlined, small)
transform: 'translate(14px, -9px) scale(0.75)' (outlined, shrink)
transform: 'translate(12px, 16px) scale(1)' (filled, default), and corresponding small/shrink variants
maxWidth: 'calc(100% - 24px)', maxWidth: 'calc(133% - 32px)' (outlined)
The horizontal 14px translate in the outlined InputLabel only aligns with the field because it happens to match the 14px horizontal padding of OutlinedInput. The two files maintain this contract by hand, and the constants 24px / 32px / 133% further depend on it.
I'd like these spacing values to be lifted into the theme so that they're a public, documented surface — ideally so that overriding the input's horizontal padding automatically propagates to the label's transform.
Internally OutlinedInput would derive its padding from those tokens, and InputLabel would derive the X component of its translate from the same paddingX (and the Y component from paddingY plus the label's font metrics). Today both numbers are written by hand in two files.
The same pattern repeats in FilledInput.js (e.g. padding: '25px 12px 8px', padding: '21px 12px 4px' for small, plus adornment-specific overrides) and to a lesser extent in Input.js and InputBase.js. Each file maintains its own set of literals that need to stay coordinated with InputLabel's filled / standard transform blocks, so the problem is structural across the input family rather than specific to OutlinedInput. Note that startAdornment / endAdornment introduce yet another layer: they don't tweak the existing padding token, they overwrite it with their own hardcoded 14px, so any override has to be re-applied conditionally for the adornment case.
I'm aware styleOverrides lets you reach these styles in principle, so this isn't strictly "impossible". But because the values live inside variants: blocks, are spread across two component slots and two files, and are tied together by an undocumented contract, doing it correctly requires re-deriving every magic number by hand.
Examples
The minimal failure case: override OutlinedInput to use a non-default horizontal padding, e.g.
MuiOutlinedInput: {
styleOverrides: {
root: { '& .MuiOutlinedInput-input': { padding: '10px 10px' } },
},
},
Now the shrunk InputLabel floats at translate(14px, -9px) while the notched outline cutout starts at 10px from the left — the label sits inside-but-misaligned. To fix it you have to additionally override MuiInputLabel.styleOverrides.outlined with a hand-computed transform, and repeat the exercise for size="small" and the shrink state.
Material Design's own text-field spec defines internal spacing semantically (edge insets, baseline alignment) rather than as fixed pixels, so making these configurable is, if anything, closer to the spec than the current hardcoded numbers.
Motivation
The built-in size: 'small' | 'medium' only gives two discrete density steps. Real-world design systems built on top of Material UI commonly need:
- Redefining the default
medium and small themselves, not just adding extra steps — so that the baseline <TextField /> already matches the host design system without consumers having to opt into a custom size everywhere.
- Adding further density steps (e.g. "compact" or "comfortable") beyond small/medium when needed.
- Slightly adjusted horizontal padding so text fields align with adjacent custom-sized buttons, selects, or chips.
- Density tweaks for CJK content, where body line-height and x-height differ enough from the Roboto-tuned defaults to make the stock paddings feel off.
Currently, achieving any of this means overriding MuiOutlinedInput.styleOverrides.root, MuiOutlinedInput.styleOverrides.input, and MuiInputLabel.styleOverrides.outlined in sync, and re-deriving every constant (16.5, 8.5, 14, 9, -9, 24, 32, 133%) by hand. None of these are documented as a public API, which means they could legitimately change between minor versions.
Promoting them to named theme tokens would:
- Reduce a multi-component override cascade to a single token change.
- Make the implicit input-padding <-> label-transform contract explicit and documented.
- Bring text-field density into line with the rest of MUI's theming surface (
shape, spacing, typography).
Search keywords: OutlinedInput padding hardcoded, InputLabel transform hardcoded, TextField density customization, InputLabel alignment, theme spacing tokens
Summary
The
TextField/OutlinedInput/Inputcomponents have several spacing values written as literal numbers inside theirstyled()definitions, rather than being exposed as theme tokens. The same is true ofInputLabel, whosetransform: translate(x, y)values are implicitly coupled to the input's padding but are themselves hardcoded in a separate file.In OutlinedInput.js the relevant literals include:
paddingLeft: 14(whenstartAdornmentis present)paddingRight: 14(whenendAdornmentis present)padding: '16.5px 14px'(multiline, default)padding: '8.5px 14px'(multiline,size="small")padding: '16.5px 14px'/padding: '8.5px 14px'onOutlinedInputInputIn InputLabel.js the matching label positions are also literal:
transform: 'translate(14px, 16px) scale(1)'(outlined, default)transform: 'translate(14px, 9px) scale(1)'(outlined, small)transform: 'translate(14px, -9px) scale(0.75)'(outlined, shrink)transform: 'translate(12px, 16px) scale(1)'(filled, default), and corresponding small/shrink variantsmaxWidth: 'calc(100% - 24px)',maxWidth: 'calc(133% - 32px)'(outlined)The horizontal
14pxtranslate in the outlinedInputLabelonly aligns with the field because it happens to match the14pxhorizontal padding ofOutlinedInput. The two files maintain this contract by hand, and the constants24px/32px/133%further depend on it.I'd like these spacing values to be lifted into the theme so that they're a public, documented surface — ideally so that overriding the input's horizontal padding automatically propagates to the label's transform.
Internally
OutlinedInputwould derive itspaddingfrom those tokens, andInputLabelwould derive the X component of itstranslatefrom the samepaddingX(and the Y component frompaddingYplus the label's font metrics). Today both numbers are written by hand in two files.The same pattern repeats in
FilledInput.js(e.g.padding: '25px 12px 8px',padding: '21px 12px 4px'for small, plus adornment-specific overrides) and to a lesser extent inInput.jsandInputBase.js. Each file maintains its own set of literals that need to stay coordinated withInputLabel'sfilled/standardtransform blocks, so the problem is structural across the input family rather than specific toOutlinedInput. Note thatstartAdornment/endAdornmentintroduce yet another layer: they don't tweak the existing padding token, they overwrite it with their own hardcoded14px, so any override has to be re-applied conditionally for the adornment case.I'm aware
styleOverrideslets you reach these styles in principle, so this isn't strictly "impossible". But because the values live insidevariants:blocks, are spread across two component slots and two files, and are tied together by an undocumented contract, doing it correctly requires re-deriving every magic number by hand.Examples
The minimal failure case: override
OutlinedInputto use a non-default horizontal padding, e.g.Now the shrunk
InputLabelfloats attranslate(14px, -9px)while the notched outline cutout starts at10pxfrom the left — the label sits inside-but-misaligned. To fix it you have to additionally overrideMuiInputLabel.styleOverrides.outlinedwith a hand-computed transform, and repeat the exercise forsize="small"and the shrink state.Material Design's own text-field spec defines internal spacing semantically (edge insets, baseline alignment) rather than as fixed pixels, so making these configurable is, if anything, closer to the spec than the current hardcoded numbers.
Motivation
The built-in
size: 'small' | 'medium'only gives two discrete density steps. Real-world design systems built on top of Material UI commonly need:mediumandsmallthemselves, not just adding extra steps — so that the baseline<TextField />already matches the host design system without consumers having to opt into a custom size everywhere.Currently, achieving any of this means overriding
MuiOutlinedInput.styleOverrides.root,MuiOutlinedInput.styleOverrides.input, andMuiInputLabel.styleOverrides.outlinedin sync, and re-deriving every constant (16.5,8.5,14,9,-9,24,32,133%) by hand. None of these are documented as a public API, which means they could legitimately change between minor versions.Promoting them to named theme tokens would:
shape,spacing,typography).Search keywords: OutlinedInput padding hardcoded, InputLabel transform hardcoded, TextField density customization, InputLabel alignment, theme spacing tokens