diff --git a/docs/pages/api-docs/outlined-input.json b/docs/pages/api-docs/outlined-input.json
index 78e1975ce8ea9a..d6ae6faadee1b2 100644
--- a/docs/pages/api-docs/outlined-input.json
+++ b/docs/pages/api-docs/outlined-input.json
@@ -27,6 +27,7 @@
"required": { "type": { "name": "bool" } },
"rows": { "type": { "name": "union", "description": "number
| string" } },
"startAdornment": { "type": { "name": "node" } },
+ "sx": { "type": { "name": "object" } },
"type": { "type": { "name": "string" }, "default": "'text'" },
"value": { "type": { "name": "any" } }
},
@@ -57,6 +58,6 @@
"filename": "/packages/material-ui/src/OutlinedInput/OutlinedInput.js",
"inheritance": { "component": "InputBase", "pathname": "/api/input-base/" },
"demos": "
",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/translations/api-docs/outlined-input/outlined-input.json b/docs/translations/api-docs/outlined-input/outlined-input.json
index c0beed450ac777..ebedb599a939d0 100644
--- a/docs/translations/api-docs/outlined-input/outlined-input.json
+++ b/docs/translations/api-docs/outlined-input/outlined-input.json
@@ -28,6 +28,7 @@
"required": "If true
, the input
element is required. The prop defaults to the value (false
) inherited from the parent FormControl component.",
"rows": "Number of rows to display when multiline option is set to true.",
"startAdornment": "Start InputAdornment
for this component.",
+ "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.",
"type": "Type of the input
element. It should be a valid HTML5 input type.",
"value": "The value of the input
element, required for a controlled component."
},
diff --git a/packages/material-ui/src/Autocomplete/Autocomplete.js b/packages/material-ui/src/Autocomplete/Autocomplete.js
index d6527e4fe18416..6142e40a4862b9 100644
--- a/packages/material-ui/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui/src/Autocomplete/Autocomplete.js
@@ -159,7 +159,7 @@ const AutocompleteRoot = experimentalStyled(
padding: '2px 4px 3px 0',
},
},
- '&[class*="MuiOutlinedInput-root"]': {
+ '&.MuiOutlinedInput-root': {
padding: 9,
[`.${autocompleteClasses.hasPopupIcon}&, .${autocompleteClasses.hasClearIcon}&`]: {
paddingRight: 26 + 4 + 9,
@@ -167,16 +167,16 @@ const AutocompleteRoot = experimentalStyled(
[`.${autocompleteClasses.hasPopupIcon}.${autocompleteClasses.hasClearIcon}&`]: {
paddingRight: 52 + 4 + 9,
},
- [`& .${autocompleteClasses.input}`]: {
+ '& .MuiOutlinedInput-input': {
padding: '7.5px 4px 7.5px 6px',
},
[`& .${autocompleteClasses.endAdornment}`]: {
right: 9,
},
},
- '&[class*="MuiOutlinedInput-root"][class*="MuiOutlinedInput-sizeSmall"]': {
+ '&.MuiOutlinedInput-root.MuiInputBase-sizeSmall': {
padding: 6,
- [`& .${autocompleteClasses.input}`]: {
+ '& .MuiOutlinedInput-input': {
padding: '2.5px 4px 2.5px 6px',
},
},
diff --git a/packages/material-ui/src/OutlinedInput/NotchedOutline.js b/packages/material-ui/src/OutlinedInput/NotchedOutline.js
index 36bb1ad4386bf9..a4178113b9e345 100644
--- a/packages/material-ui/src/OutlinedInput/NotchedOutline.js
+++ b/packages/material-ui/src/OutlinedInput/NotchedOutline.js
@@ -1,39 +1,43 @@
import * as React from 'react';
import PropTypes from 'prop-types';
-import clsx from 'clsx';
-import withStyles from '../styles/withStyles';
import useTheme from '../styles/useTheme';
import capitalize from '../utils/capitalize';
+import experimentalStyled from '../styles/experimentalStyled';
-export const styles = (theme) => {
+const NotchedOutlineRoot = experimentalStyled(
+ 'fieldset',
+ {},
+ { name: 'PrivateNotchedOutline', slot: 'Root' },
+)(() => ({
+ textAlign: 'left',
+ position: 'absolute',
+ bottom: 0,
+ right: 0,
+ top: -5,
+ left: 0,
+ margin: 0,
+ padding: '0 8px',
+ pointerEvents: 'none',
+ borderRadius: 'inherit',
+ borderStyle: 'solid',
+ borderWidth: 1,
+ overflow: 'hidden',
+}));
+const NotchedOutlineLegend = experimentalStyled(
+ 'legend',
+ {},
+ { name: 'PrivateNotchedOutline', slot: 'Legend' },
+)(({ styleProps, theme }) => {
return {
- /* Styles applied to the root element. */
- root: {
- textAlign: 'left',
- position: 'absolute',
- bottom: 0,
- right: 0,
- top: -5,
- left: 0,
- margin: 0,
- padding: '0 8px',
- pointerEvents: 'none',
- borderRadius: 'inherit',
- borderStyle: 'solid',
- borderWidth: 1,
- overflow: 'hidden',
- },
- /* Styles applied to the legend element when `labelWidth` is provided. */
- legend: {
+ ...(styleProps.label === undefined && {
padding: 0,
lineHeight: '11px', // sync with `height` in `legend` styles
transition: theme.transitions.create('width', {
duration: 150,
easing: theme.transitions.easing.easeOut,
}),
- },
- /* Styles applied to the legend element. */
- legendLabelled: {
+ }),
+ ...(styleProps.label !== undefined && {
display: 'block',
width: 'auto',
padding: 0,
@@ -50,18 +54,17 @@ export const styles = (theme) => {
paddingRight: 5,
display: 'inline-block',
},
- },
- /* Styles applied to the legend element is notched. */
- legendNotched: {
- maxWidth: 1000,
- transition: theme.transitions.create('max-width', {
- duration: 100,
- easing: theme.transitions.easing.easeOut,
- delay: 50,
+ ...(styleProps.notched && {
+ maxWidth: 1000,
+ transition: theme.transitions.create('max-width', {
+ duration: 100,
+ easing: theme.transitions.easing.easeOut,
+ delay: 50,
+ }),
}),
- },
+ }),
};
-};
+});
/**
* @ignore - internal component.
@@ -79,21 +82,22 @@ const NotchedOutline = React.forwardRef(function NotchedOutline(props, ref) {
} = props;
const theme = useTheme();
const align = theme.direction === 'rtl' ? 'right' : 'left';
-
+ const styleProps = {
+ ...props,
+ notched,
+ label,
+ };
if (label !== undefined) {
return (
-
+
+
);
}
@@ -111,18 +115,19 @@ const NotchedOutline = React.forwardRef(function NotchedOutline(props, ref) {
// TODO remove this branch
return (
-
+
+
);
});
@@ -171,4 +176,4 @@ NotchedOutline.propTypes = {
style: PropTypes.object,
};
-export default withStyles(styles, { name: 'PrivateNotchedOutline' })(NotchedOutline);
+export default NotchedOutline;
diff --git a/packages/material-ui/src/OutlinedInput/NotchedOutline.test.js b/packages/material-ui/src/OutlinedInput/NotchedOutline.test.js
index 40b4eadffd2de8..0308c07f3a5967 100644
--- a/packages/material-ui/src/OutlinedInput/NotchedOutline.test.js
+++ b/packages/material-ui/src/OutlinedInput/NotchedOutline.test.js
@@ -1,23 +1,18 @@
import * as React from 'react';
import { expect } from 'chai';
-import { getClasses, createClientRender } from 'test/utils';
+import { createClientRender } from 'test/utils';
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import NotchedOutline from './NotchedOutline';
describe('', () => {
const render = createClientRender();
- let classes;
const defaultProps = {
labelWidth: 36,
notched: true,
label: 'My label',
};
- before(() => {
- classes = getClasses();
- });
-
it('should pass props', () => {
const { container } = render(
', () => {
expect(container.querySelector('fieldset')).to.have.class('notched-outline');
expect(container.querySelector('fieldset').style.width).to.equal('17px');
- expect(container.querySelector('legend')).to.have.class(classes.legendNotched);
});
it('should set alignment rtl', () => {
diff --git a/packages/material-ui/src/OutlinedInput/OutlinedInput.d.ts b/packages/material-ui/src/OutlinedInput/OutlinedInput.d.ts
index 88f94f8984d30a..0f26b936be4ed7 100644
--- a/packages/material-ui/src/OutlinedInput/OutlinedInput.d.ts
+++ b/packages/material-ui/src/OutlinedInput/OutlinedInput.d.ts
@@ -1,5 +1,6 @@
import * as React from 'react';
-import { InternalStandardProps as StandardProps } from '..';
+import { SxProps } from '@material-ui/system';
+import { InternalStandardProps as StandardProps, Theme } from '..';
import { InputBaseProps } from '../InputBase';
export interface OutlinedInputProps extends StandardProps {
@@ -53,6 +54,10 @@ export interface OutlinedInputProps extends StandardProps {
* If `true`, the outline is notched to accommodate the label.
*/
notched?: boolean;
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx?: SxProps;
}
export type OutlinedInputClassKey = keyof NonNullable;
diff --git a/packages/material-ui/src/OutlinedInput/OutlinedInput.js b/packages/material-ui/src/OutlinedInput/OutlinedInput.js
index 43c328f5c87ee8..4176d7b5846a36 100644
--- a/packages/material-ui/src/OutlinedInput/OutlinedInput.js
+++ b/packages/material-ui/src/OutlinedInput/OutlinedInput.js
@@ -1,111 +1,143 @@
import * as React from 'react';
import PropTypes from 'prop-types';
-import clsx from 'clsx';
-import { refType } from '@material-ui/utils';
-import InputBase from '../InputBase';
+
+import { deepmerge, refType } from '@material-ui/utils';
+import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import NotchedOutline from './NotchedOutline';
-import withStyles from '../styles/withStyles';
+import experimentalStyled, { shouldForwardProp } from '../styles/experimentalStyled';
+import outlinedInputClasses, { getOutlinedInputUtilityClass } from './outlinedInputClasses';
+import InputBase, {
+ overridesResolver as inputBaseOverridesResolver,
+ InputBaseRoot,
+ InputBaseComponent as InputBaseInput,
+} from '../InputBase/InputBase';
+import useThemeProps from '../styles/useThemeProps';
-export const styles = (theme) => {
- const borderColor =
- theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';
+const overridesResolver = (props, styles) => {
+ return deepmerge(inputBaseOverridesResolver(props, styles), {
+ ...styles.notchedOutline,
+ });
+};
- return {
- /* Styles applied to the root element. */
- root: {
+const useUtilityClasses = (styleProps) => {
+ const { classes } = styleProps;
+
+ const slots = {
+ root: ['root'],
+ notchedOutline: ['notchedOutline'],
+ input: ['input'],
+ };
+
+ return composeClasses(slots, getOutlinedInputUtilityClass, classes);
+};
+
+const OutlinedInputRoot = experimentalStyled(
+ InputBaseRoot,
+ { shouldForwardProp: (prop) => shouldForwardProp(prop) || prop === 'classes' },
+ { name: 'MuiOutlinedInput', slot: 'Root', overridesResolver },
+)(
+ ({ theme, styleProps }) => {
+ const borderColor =
+ theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';
+ return {
position: 'relative',
borderRadius: theme.shape.borderRadius,
- '&:hover $notchedOutline': {
- borderColor: theme.palette.text.primary,
+ '&:hover': {
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
+ borderColor: theme.palette.text.primary,
+ },
},
// Reset on touch devices, it doesn't add specificity
'@media (hover: none)': {
- '&:hover $notchedOutline': {
- borderColor,
+ '&:hover': {
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
+ borderColor,
+ },
},
},
- '&$focused $notchedOutline': {
- borderColor: theme.palette.primary.main,
- borderWidth: 2,
- },
- '&$error $notchedOutline': {
- borderColor: theme.palette.error.main,
- },
- '&$disabled $notchedOutline': {
- borderColor: theme.palette.action.disabled,
- },
- },
- /* Styles applied to the root element if the color is secondary. */
- colorSecondary: {
- '&$focused $notchedOutline': {
- borderColor: theme.palette.secondary.main,
+ [`&.Mui-focused`]: {
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
+ borderColor: theme.palette.primary.main,
+ borderWidth: 2,
+ },
},
- '&$error $notchedOutline': {
- // To remove once we migrate to emotion
- borderColor: theme.palette.error.main,
+ '&.Mui-error': {
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
+ borderColor: theme.palette.error.main,
+ },
},
- },
- /* Styles applied to the root element if the component is focused. */
- focused: {},
- /* Styles applied to the root element if `disabled={true}`. */
- disabled: {},
- /* Styles applied to the root element if `startAdornment` is provided. */
- adornedStart: {
- paddingLeft: 14,
- },
- /* Styles applied to the root element if `endAdornment` is provided. */
- adornedEnd: {
- paddingRight: 14,
- },
- /* Pseudo-class applied to the root element if `error={true}`. */
- error: {},
- /* Styles applied to the input element if `size="small"`. */
- sizeSmall: {},
- /* Styles applied to the root element if `multiline={true}`. */
- multiline: {
- padding: '16.5px 14px',
- '&$sizeSmall': {
- paddingTop: 10.5,
- paddingBottom: 10.5,
+ '&.Mui-disabled': {
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
+ borderColor: theme.palette.action.disabled,
+ },
},
- },
- /* Styles applied to the NotchedOutline element. */
- notchedOutline: {
- borderColor,
- },
- /* Styles applied to the input element. */
- input: {
- padding: '16.5px 14px',
- '&:-webkit-autofill': {
- WebkitBoxShadow: theme.palette.mode === 'light' ? null : '0 0 0 100px #266798 inset',
- WebkitTextFillColor: theme.palette.mode === 'light' ? null : '#fff',
- caretColor: theme.palette.mode === 'light' ? null : '#fff',
- borderRadius: 'inherit',
+ ...(styleProps.startAdornment && {
+ paddingLeft: 14,
+ }),
+ ...(styleProps.endAdornment && {
+ paddingRight: 14,
+ }),
+ ...(styleProps.multiline && {
+ padding: '16.5px 14px',
+ ...(styleProps.size === 'small' && {
+ paddingTop: 10.5,
+ paddingBottom: 10.5,
+ }),
+ }),
+ };
+ },
+ ({ styleProps, theme }) => ({
+ ...(styleProps.color === 'secondary' && {
+ '&.Mui-focused': {
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
+ borderColor: theme.palette.secondary.main,
+ },
},
- },
- /* Styles applied to the input element if `size="small"`. */
- inputSizeSmall: {
- paddingTop: 8.5,
- paddingBottom: 8.5,
- },
- /* Styles applied to the input element if `multiline={true}`. */
- inputMultiline: {
- padding: 0,
- },
- /* Styles applied to the input element if `startAdornment` is provided. */
- inputAdornedStart: {
- paddingLeft: 0,
- },
- /* Styles applied to the input element if `endAdornment` is provided. */
- inputAdornedEnd: {
- paddingRight: 0,
- },
- };
-};
+ }),
+ }),
+);
+
+const NotchedOutlineRoot = experimentalStyled(
+ NotchedOutline,
+ {},
+ { name: 'MuiOutlinedInput', slot: 'NotchedOutline' },
+)(({ theme }) => {
+ const borderColor =
+ theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';
+ return { borderColor };
+});
+
+const OutlinedInputInput = experimentalStyled(
+ InputBaseInput,
+ { shouldForwardProp: (prop) => shouldForwardProp(prop) || prop === 'classes' },
+ { name: 'MuiOutlinedInput', slot: 'Input' },
+)(({ theme, styleProps }) => ({
+ padding: '16.5px 14px',
+ '&:-webkit-autofill': {
+ WebkitBoxShadow: theme.palette.mode === 'light' ? null : '0 0 0 100px #266798 inset',
+ WebkitTextFillColor: theme.palette.mode === 'light' ? null : '#fff',
+ caretColor: theme.palette.mode === 'light' ? null : '#fff',
+ borderRadius: 'inherit',
+ },
+ ...(styleProps.size === 'small' && {
+ paddingTop: 8.5,
+ paddingBottom: 8.5,
+ }),
+ ...(styleProps.multiline && {
+ padding: 0,
+ }),
+ ...(styleProps.startAdornment && {
+ paddingLeft: 0,
+ }),
+ ...(styleProps.endAdornment && {
+ paddingRight: 0,
+ }),
+}));
+
+const OutlinedInput = React.forwardRef(function OutlinedInput(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiOutlinedInput' });
-const OutlinedInput = React.forwardRef(function OutlinedInput(props, ref) {
const {
- classes,
fullWidth = false,
inputComponent = 'input',
label,
@@ -116,10 +148,23 @@ const OutlinedInput = React.forwardRef(function OutlinedInput(props, ref) {
...other
} = props;
+ const styleProps = {
+ ...props,
+ fullWidth,
+ inputComponent,
+ labelWidth,
+ multiline,
+ type,
+ };
+
+ const classes = useUtilityClasses(props);
+
return (
(
-
)}
- classes={{
- ...classes,
- root: clsx(classes.root, classes.underline),
- notchedOutline: null,
- }}
+ classes={classes}
fullWidth={fullWidth}
inputComponent={inputComponent}
multiline={multiline}
@@ -278,6 +319,10 @@ OutlinedInput.propTypes = {
* Start `InputAdornment` for this component.
*/
startAdornment: PropTypes.node,
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx: PropTypes.object,
/**
* Type of the `input` element. It should be [a valid HTML5 input type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types).
* @default 'text'
@@ -291,4 +336,4 @@ OutlinedInput.propTypes = {
OutlinedInput.muiName = 'Input';
-export default withStyles(styles, { name: 'MuiOutlinedInput' })(OutlinedInput);
+export default OutlinedInput;
diff --git a/packages/material-ui/src/OutlinedInput/OutlinedInput.test.js b/packages/material-ui/src/OutlinedInput/OutlinedInput.test.js
index c10285622e618c..70d543955747d6 100644
--- a/packages/material-ui/src/OutlinedInput/OutlinedInput.test.js
+++ b/packages/material-ui/src/OutlinedInput/OutlinedInput.test.js
@@ -1,24 +1,24 @@
import * as React from 'react';
import { expect } from 'chai';
-import { getClasses, createMount, createClientRender, describeConformance } from 'test/utils';
+import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import OutlinedInput from './OutlinedInput';
import InputBase from '../InputBase';
+import classes from './outlinedInputClasses';
describe('', () => {
- let classes;
const mount = createMount();
const render = createClientRender();
- before(() => {
- classes = getClasses();
- });
-
- describeConformance(, () => ({
+ describeConformanceV5(, () => ({
classes,
inheritComponent: InputBase,
mount,
refInstanceof: window.HTMLDivElement,
- skip: ['componentProp'],
+ muiName: 'MuiOutlinedInput',
+ testDeepOverrides: { slotName: 'input', slotClassName: classes.input },
+ testVariantProps: { variant: 'contained', fullWidth: true },
+ testStateOverrides: { prop: 'size', value: 'small', styleKey: 'sizeSmall' },
+ skip: ['componentProp', 'componentsProp'],
}));
it('should render a NotchedOutline', () => {
diff --git a/packages/material-ui/src/OutlinedInput/index.d.ts b/packages/material-ui/src/OutlinedInput/index.d.ts
index 330ce05397b8f7..56e72dcf01e7e7 100644
--- a/packages/material-ui/src/OutlinedInput/index.d.ts
+++ b/packages/material-ui/src/OutlinedInput/index.d.ts
@@ -1,2 +1,4 @@
export { default } from './OutlinedInput';
export * from './OutlinedInput';
+export { default as outlinedInputClasses } from './outlinedInputClasses';
+export * from './outlinedInputClasses';
diff --git a/packages/material-ui/src/OutlinedInput/index.js b/packages/material-ui/src/OutlinedInput/index.js
index 56d43aaaaf69e4..09bd8d68e617d9 100644
--- a/packages/material-ui/src/OutlinedInput/index.js
+++ b/packages/material-ui/src/OutlinedInput/index.js
@@ -1 +1,3 @@
export { default } from './OutlinedInput';
+export { default as outlinedInputClasses } from './outlinedInputClasses';
+export * from './outlinedInputClasses';
diff --git a/packages/material-ui/src/OutlinedInput/outlinedInputClasses.d.ts b/packages/material-ui/src/OutlinedInput/outlinedInputClasses.d.ts
new file mode 100644
index 00000000000000..4f412f2e938137
--- /dev/null
+++ b/packages/material-ui/src/OutlinedInput/outlinedInputClasses.d.ts
@@ -0,0 +1,7 @@
+import { OutlinedInputClassKey } from './OutlinedInput';
+
+declare const outlinedInputClasses: Record;
+
+export function getOutlinedInputUtilityClasses(slot: string): string;
+
+export default outlinedInputClasses;
diff --git a/packages/material-ui/src/OutlinedInput/outlinedInputClasses.js b/packages/material-ui/src/OutlinedInput/outlinedInputClasses.js
new file mode 100644
index 00000000000000..a926d5b86b69e6
--- /dev/null
+++ b/packages/material-ui/src/OutlinedInput/outlinedInputClasses.js
@@ -0,0 +1,13 @@
+import { generateUtilityClasses, generateUtilityClass } from '@material-ui/unstyled';
+
+export function getOutlinedInputUtilityClass(slot) {
+ return generateUtilityClass('MuiOutlinedInput', slot);
+}
+
+const outlinedInputClasses = generateUtilityClasses('MuiOutlinedInput', [
+ 'root',
+ 'notchedOutline',
+ 'input',
+]);
+
+export default outlinedInputClasses;
diff --git a/packages/material-ui/src/TextField/TextField.test.js b/packages/material-ui/src/TextField/TextField.test.js
index 0a189e3b9e354f..979ad67f66c002 100644
--- a/packages/material-ui/src/TextField/TextField.test.js
+++ b/packages/material-ui/src/TextField/TextField.test.js
@@ -2,10 +2,10 @@ import * as React from 'react';
import { expect } from 'chai';
import { getClasses, createMount, createClientRender, describeConformance } from 'test/utils';
import FormControl from '../FormControl';
-import OutlinedInput from '../OutlinedInput';
import TextField from './TextField';
import MenuItem from '../MenuItem';
import { inputBaseClasses } from '../InputBase';
+import { outlinedInputClasses } from '../OutlinedInput';
describe('', () => {
let classes;
@@ -126,7 +126,6 @@ describe('', () => {
});
it('should set shrink prop on outline from label', () => {
- const outlinedInputClasses = getClasses();
const { container } = render();
expect(container.querySelector('fieldset')).to.have.class(