diff --git a/docs/data/base/components/input/input.md b/docs/data/base/components/input/input.md index 6100658cbe7f75..f42d11590e2139 100644 --- a/docs/data/base/components/input/input.md +++ b/docs/data/base/components/input/input.md @@ -54,27 +54,17 @@ The Input component is composed of a root `
` slot that houses one interior
``` -### Slot props +### Custom structure -:::info -The following props are available on all non-utility Base components. -See [Usage](/base/getting-started/usage/) for full details. -::: - -Use the `component` prop to override the root slot with a custom element: - -```jsx - -``` - -Use the `slots` prop to override any interior slots in addition to the root: +Use the `slots` prop to override the root or any other interior slot: ```jsx - + ``` -:::warning -If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. +:::info +The `slots` prop is available on all non-utility Base components. +See [Overriding component structure](/base/guides/overriding-component-structure/) for full details. ::: Use the `slotProps` prop to pass custom props to internal slots. @@ -84,6 +74,20 @@ The following code snippet applies a CSS class called `my-input` to the input sl ``` +#### Usage with TypeScript + +In TypeScript, you can specify the custom component type used in the `slots.root` as a generic parameter of the unstyled component. This way, you can safely provide the custom root's props directly on the component: + +```tsx + slots={{ root: CustomComponent }} customProp /> +``` + +The same applies for props specific to custom primitive elements: + +```tsx + slots={{ root: 'textarea' }} rows={2} /> +``` + ## Hook ```js diff --git a/docs/pages/base/api/input.json b/docs/pages/base/api/input.json index f35a4b3eaf4a6a..980af136f07548 100644 --- a/docs/pages/base/api/input.json +++ b/docs/pages/base/api/input.json @@ -3,7 +3,6 @@ "autoComplete": { "type": { "name": "string" } }, "autoFocus": { "type": { "name": "bool" } }, "className": { "type": { "name": "string" } }, - "component": { "type": { "name": "elementType" } }, "defaultValue": { "type": { "name": "any" } }, "disabled": { "type": { "name": "bool" } }, "endAdornment": { "type": { "name": "node" } }, diff --git a/docs/translations/api-docs-base/input/input.json b/docs/translations/api-docs-base/input/input.json index 2853be93336b60..604e11cb95e78e 100644 --- a/docs/translations/api-docs-base/input/input.json +++ b/docs/translations/api-docs-base/input/input.json @@ -4,7 +4,6 @@ "autoComplete": "This prop helps users to fill forms faster, especially on mobile devices. The name can be confusing, as it's more like an autofill. You can learn more about it following the specification.", "autoFocus": "If true, the input element is focused during the first mount.", "className": "Class name applied to the root element.", - "component": "The component used for the root node. Either a string to use a HTML element or a component.", "defaultValue": "The default value. Use when the component is not controlled.", "disabled": "If true, the component is disabled. The prop defaults to the value (false) inherited from the parent FormControl component.", "endAdornment": "Trailing adornment for this input.", diff --git a/packages/mui-base/src/Input/Input.spec.tsx b/packages/mui-base/src/Input/Input.spec.tsx index f75c39e22835d7..1fe1463fef4c8b 100644 --- a/packages/mui-base/src/Input/Input.spec.tsx +++ b/packages/mui-base/src/Input/Input.spec.tsx @@ -31,19 +31,38 @@ const polymorphicComponentTest = () => { {/* @ts-expect-error */} - + + slots={{ + root: 'a', + }} + href="#" + /> - + + slots={{ + root: CustomComponent, + }} + stringProp="test" + numberProp={0} + /> {/* @ts-expect-error */} - + + slots={{ + root: CustomComponent, + }} + /> - + slots={{ + root: 'button', + }} onClick={(e: React.MouseEvent) => e.currentTarget.checkValidity()} /> - component="button" + slots={{ + root: 'button', + }} ref={(elem) => { expectType(elem); }} diff --git a/packages/mui-base/src/Input/Input.test.tsx b/packages/mui-base/src/Input/Input.test.tsx index 6a0e92ca71acf4..b7c537c132a048 100644 --- a/packages/mui-base/src/Input/Input.test.tsx +++ b/packages/mui-base/src/Input/Input.test.tsx @@ -23,6 +23,7 @@ describe('', () => { testWithElement: 'input', }, }, + skip: ['componentProp'], })); it('should render textarea without any console errors when multiline=true', () => { diff --git a/packages/mui-base/src/Input/Input.tsx b/packages/mui-base/src/Input/Input.tsx index 2ce2cad7adc565..2929059bd48c32 100644 --- a/packages/mui-base/src/Input/Input.tsx +++ b/packages/mui-base/src/Input/Input.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { OverridableComponent } from '@mui/types'; +import { PolymorphicComponent } from '../utils/PolymorphicComponent'; import isHostComponent from '../utils/isHostComponent'; import { getInputUtilityClass } from './inputClasses'; import { @@ -57,7 +57,6 @@ const Input = React.forwardRef(function Input = useSlotProps({ elementType: Root, getSlotProps: getRootProps, @@ -182,7 +181,7 @@ const Input = React.forwardRef(function Input ); -}) as OverridableComponent; +}) as PolymorphicComponent; Input.propTypes /* remove-proptypes */ = { // ----------------------------- Warning -------------------------------- @@ -211,23 +210,10 @@ Input.propTypes /* remove-proptypes */ = { * If `true`, the `input` element is focused during the first mount. */ autoFocus: PropTypes.bool, - /** - * @ignore - */ - children: PropTypes.node, /** * Class name applied to the root element. */ className: PropTypes.string, - /** - * @ignore - */ - color: PropTypes.string, - /** - * The component used for the root node. - * Either a string to use a HTML element or a component. - */ - component: PropTypes.elementType, /** * The default value. Use when the component is not controlled. */ diff --git a/packages/mui-base/src/Input/Input.types.ts b/packages/mui-base/src/Input/Input.types.ts index 71d142d22defe5..e2b0a9e0ae96c0 100644 --- a/packages/mui-base/src/Input/Input.types.ts +++ b/packages/mui-base/src/Input/Input.types.ts @@ -1,8 +1,8 @@ import * as React from 'react'; -import { OverrideProps, Simplify } from '@mui/types'; +import { Simplify } from '@mui/types'; import { FormControlState } from '../FormControl'; import { UseInputParameters, UseInputRootSlotProps } from '../useInput'; -import { SlotComponentProps } from '../utils'; +import { PolymorphicProps, SlotComponentProps } from '../utils'; export interface InputRootSlotPropsOverrides {} export interface InputInputSlotPropsOverrides {} @@ -156,9 +156,7 @@ export interface InputTypeMap< export type InputProps< RootComponentType extends React.ElementType = InputTypeMap['defaultComponent'], -> = OverrideProps, RootComponentType> & { - component?: RootComponentType; -}; +> = PolymorphicProps, RootComponentType>; export type InputOwnerState = Simplify< InputOwnProps & {