diff --git a/docs/pages/api-docs/button-base.json b/docs/pages/api-docs/button-base.json index e201f31e99e844..cd2ae650a24f7c 100644 --- a/docs/pages/api-docs/button-base.json +++ b/docs/pages/api-docs/button-base.json @@ -10,6 +10,7 @@ "disableTouchRipple": { "type": { "name": "bool" } }, "focusRipple": { "type": { "name": "bool" } }, "focusVisibleClassName": { "type": { "name": "string" } }, + "LinkComponent": { "type": { "name": "elementType" }, "default": "'a'" }, "onFocusVisible": { "type": { "name": "func" } }, "sx": { "type": { "name": "object" } }, "TouchRippleProps": { "type": { "name": "object" } } diff --git a/docs/pages/guides/routing.js b/docs/pages/guides/routing.js new file mode 100644 index 00000000000000..04b21f34057898 --- /dev/null +++ b/docs/pages/guides/routing.js @@ -0,0 +1,20 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import { prepareMarkdown } from 'docs/src/modules/utils/parseMarkdown'; + +const pageFilename = 'guides/routing'; +const requireDemo = require.context('docs/src/pages/guides/routing', false, /\.(js|tsx)$/); +const requireRaw = require.context( + '!raw-loader!../../src/pages/guides/routing', + false, + /\.(js|md|tsx)$/, +); + +export default function Page({ demos, docs }) { + return ; +} + +Page.getInitialProps = () => { + const { demos, docs } = prepareMarkdown({ pageFilename, requireRaw }); + return { demos, docs }; +}; diff --git a/docs/src/pages.ts b/docs/src/pages.ts index c7cafad7ffe82c..1d254181bb74fd 100644 --- a/docs/src/pages.ts +++ b/docs/src/pages.ts @@ -254,6 +254,7 @@ const pages: MuiPage[] = [ { pathname: '/guides/interoperability', title: 'Style Library Interoperability' }, { pathname: '/guides/minimizing-bundle-size' }, { pathname: '/guides/composition' }, + { pathname: '/guides/routing' }, { pathname: '/guides/server-rendering' }, { pathname: '/guides/responsive-ui', title: 'Responsive UI' }, { pathname: '/guides/pickers-migration', title: 'Migration from @material-ui/pickers' }, diff --git a/docs/src/pages/components/buttons/buttons.md b/docs/src/pages/components/buttons/buttons.md index 67ab58eb3e62bb..90d4b244d4f6cb 100644 --- a/docs/src/pages/components/buttons/buttons.md +++ b/docs/src/pages/components/buttons/buttons.md @@ -132,7 +132,7 @@ component forwards this ref to the underlying DOM node. Given that many of the interactive components rely on `ButtonBase`, you should be able to take advantage of it everywhere. -Here is an [integration example with react-router](/guides/composition/#button). +Here is an [integration example with react-router](/guides/routing/#button). ## Limitations diff --git a/docs/src/pages/components/links/Links.js b/docs/src/pages/components/links/Links.js index 719afc4361ff55..701739ab1f6de6 100644 --- a/docs/src/pages/components/links/Links.js +++ b/docs/src/pages/components/links/Links.js @@ -3,9 +3,9 @@ import * as React from 'react'; import Box from '@material-ui/core/Box'; import Link from '@material-ui/core/Link'; -export default function Links() { - const preventDefault = (event) => event.preventDefault(); +const preventDefault = (event) => event.preventDefault(); +export default function Links() { return ( event.preventDefault(); +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); +export default function Links() { return ( event.preventDefault(); +const preventDefault = (event) => event.preventDefault(); +export default function UnderlineLink() { return ( event.preventDefault(); +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); +export default function UnderlineLink() { return ( ; ``` -You can find a [demo with React Router following this section](/guides/composition/#react-router) of the documentation. +You can find a [demo with React Router following this section](/guides/routing/#list) of the documentation. ## Nested List diff --git a/docs/src/pages/getting-started/faq/faq.md b/docs/src/pages/getting-started/faq/faq.md index c2631c03df10db..600f8faee1d9b6 100644 --- a/docs/src/pages/getting-started/faq/faq.md +++ b/docs/src/pages/getting-started/faq/faq.md @@ -127,7 +127,7 @@ or are already familiar with a different API, and don't want to learn a new one? [Style Library Interoperability](/guides/interoperability/) section, where we show how simple it is to restyle Material-UI components with alternative style libraries. -## When should I use inline-style vs CSS? +## When should I use inline-style vs. CSS? As a rule of thumb, only use inline-styles for dynamic style properties. The CSS alternative provides more advantages, such as: @@ -139,7 +139,7 @@ The CSS alternative provides more advantages, such as: ## How do I use react-router? -We detail the [integration with third-party routing libraries](/guides/composition/#routing-libraries) like react-router, Gatsby or Next.js in our guide. +We detail the [integration with third-party routing libraries](/guides/routing/) like react-router, Gatsby or Next.js in our guide. ## How can I access the DOM element? diff --git a/docs/src/pages/guides/composition/composition.md b/docs/src/pages/guides/composition/composition.md index 0c0aeebe07e7d8..bc2e9c159f88b7 100644 --- a/docs/src/pages/guides/composition/composition.md +++ b/docs/src/pages/guides/composition/composition.md @@ -6,7 +6,7 @@ In order to provide the maximum flexibility and performance, we need a way to know the nature of the child elements a component receives. -To solve this problem we tag some of the components +To solve this problem, we tag some of the components with a `muiName` static property when needed. You may, however, need to wrap a component in order to enhance it, @@ -128,25 +128,6 @@ The component providing the `component` prop (e.g. ListItem) might not forward a You can find the details in the [TypeScript guide](/guides/typescript/#usage-of-component-prop). -## Routing libraries - -The integration with third-party routing libraries is achieved with the `component` prop. -The behavior is identical to the description of the prop above. -Here are a few demos with [react-router-dom](https://github.com/ReactTraining/react-router). -They cover the Button, Link, and List components. You can apply the same strategy with all the components (BottomNavigation, Card, etc.). - -### Button - -{{"demo": "pages/guides/composition/ButtonRouter.js"}} - -### Link - -{{"demo": "pages/guides/composition/LinkRouter.js"}} - -### List - -{{"demo": "pages/guides/composition/ListRouter.js"}} - ## Caveat with refs This section covers caveats when using a custom component as `children` or for the diff --git a/docs/src/pages/guides/routing/ButtonDemo.js b/docs/src/pages/guides/routing/ButtonDemo.js new file mode 100644 index 00000000000000..1fc380f3638f1b --- /dev/null +++ b/docs/src/pages/guides/routing/ButtonDemo.js @@ -0,0 +1,15 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; + +const preventDefault = (event) => event.preventDefault(); + +export default function ButtonDemo() { + return ( + + + + ); +} diff --git a/docs/src/pages/guides/routing/ButtonDemo.tsx b/docs/src/pages/guides/routing/ButtonDemo.tsx new file mode 100644 index 00000000000000..eee2bfa849af0f --- /dev/null +++ b/docs/src/pages/guides/routing/ButtonDemo.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; + +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); + +export default function ButtonDemo() { + return ( + + + + ); +} diff --git a/docs/src/pages/guides/composition/ButtonRouter.js b/docs/src/pages/guides/routing/ButtonRouter.js similarity index 91% rename from docs/src/pages/guides/composition/ButtonRouter.js rename to docs/src/pages/guides/routing/ButtonRouter.js index c6865f1734736b..da65000ddd285e 100644 --- a/docs/src/pages/guides/composition/ButtonRouter.js +++ b/docs/src/pages/guides/routing/ButtonRouter.js @@ -9,14 +9,14 @@ const LinkBehavior = React.forwardRef((props, ref) => ( export default function ButtonRouter() { return ( - -
+
+
-
- + +
); } diff --git a/docs/src/pages/guides/composition/ButtonRouter.tsx b/docs/src/pages/guides/routing/ButtonRouter.tsx similarity index 92% rename from docs/src/pages/guides/composition/ButtonRouter.tsx rename to docs/src/pages/guides/routing/ButtonRouter.tsx index 4d468adaf6a337..0cbcb17272d082 100644 --- a/docs/src/pages/guides/composition/ButtonRouter.tsx +++ b/docs/src/pages/guides/routing/ButtonRouter.tsx @@ -11,14 +11,14 @@ const LinkBehavior = React.forwardRef>( export default function ButtonRouter() { return ( - -
+
+
-
- + +
); } diff --git a/docs/src/pages/guides/routing/LinkDemo.js b/docs/src/pages/guides/routing/LinkDemo.js new file mode 100644 index 00000000000000..fec5638e0ab1de --- /dev/null +++ b/docs/src/pages/guides/routing/LinkDemo.js @@ -0,0 +1,13 @@ +import * as React from 'react'; +import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; + +const preventDefault = (event) => event.preventDefault(); + +export default function LinkDemo() { + return ( + + Link + + ); +} diff --git a/docs/src/pages/guides/routing/LinkDemo.tsx b/docs/src/pages/guides/routing/LinkDemo.tsx new file mode 100644 index 00000000000000..5fba35c5a8e814 --- /dev/null +++ b/docs/src/pages/guides/routing/LinkDemo.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; + +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); + +export default function LinkDemo() { + return ( + + Link + + ); +} diff --git a/docs/src/pages/guides/composition/LinkRouter.js b/docs/src/pages/guides/routing/LinkRouter.js similarity index 83% rename from docs/src/pages/guides/composition/LinkRouter.js rename to docs/src/pages/guides/routing/LinkRouter.js index 0e4ac26cb4a1b9..9a8f2bfcf2dd90 100644 --- a/docs/src/pages/guides/composition/LinkRouter.js +++ b/docs/src/pages/guides/routing/LinkRouter.js @@ -3,6 +3,7 @@ import * as React from 'react'; import { MemoryRouter as Router } from 'react-router'; import { Link as RouterLink } from 'react-router-dom'; import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; const LinkBehavior = React.forwardRef((props, ref) => ( @@ -10,14 +11,14 @@ const LinkBehavior = React.forwardRef((props, ref) => ( export default function LinkRouter() { return ( - -
+ + With prop forwarding
Without prop forwarding -
-
+
+
); } diff --git a/docs/src/pages/guides/composition/LinkRouter.tsx b/docs/src/pages/guides/routing/LinkRouter.tsx similarity index 84% rename from docs/src/pages/guides/composition/LinkRouter.tsx rename to docs/src/pages/guides/routing/LinkRouter.tsx index 5ebbc09aa534da..ae512955c5ce8f 100644 --- a/docs/src/pages/guides/composition/LinkRouter.tsx +++ b/docs/src/pages/guides/routing/LinkRouter.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { MemoryRouter as Router } from 'react-router'; import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom'; import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; const LinkBehavior = React.forwardRef>( (props, ref) => ( @@ -12,14 +13,14 @@ const LinkBehavior = React.forwardRef>( export default function LinkRouter() { return ( - -
+ + With prop forwarding
Without prop forwarding -
-
+ +
); } diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.js b/docs/src/pages/guides/routing/LinkRouterWithTheme.js new file mode 100644 index 00000000000000..5116a38e4f5829 --- /dev/null +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.js @@ -0,0 +1,59 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { MemoryRouter as Router } from 'react-router'; +import { Link as RouterLink } from 'react-router-dom'; +import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Box from '@material-ui/core/Box'; +import Link from '@material-ui/core/Link'; + +const LinkBehavior = React.forwardRef((props, ref) => { + const { href, ...other } = props; + // Map href (Material-UI) -> to (react-router) + return ; +}); + +LinkBehavior.propTypes = { + href: PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.string]) + .isRequired, +}; + +const themeSetter = (outerTheme) => + createMuiTheme(outerTheme, { + components: { + MuiLink: { + defaultProps: { + // @ts-ignore + component: LinkBehavior, + }, + }, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, + }, + }, + }); + +export default function LinkRouterWithTheme() { + return ( + :not(style) + :not(style)': { mt: 1 }, + }} + > + + + Link + + + + + ); +} diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx new file mode 100644 index 00000000000000..cd468f8dc74f58 --- /dev/null +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx @@ -0,0 +1,56 @@ +import * as React from 'react'; +import { MemoryRouter as Router } from 'react-router'; +import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom'; +import { Theme, ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Box from '@material-ui/core/Box'; +import Link from '@material-ui/core/Link'; + +const LinkBehavior = React.forwardRef< + any, + Omit & { href: RouterLinkProps['to'] } +>((props, ref) => { + const { href, ...other } = props; + // Map href (Material-UI) -> to (react-router) + return ; +}); + +const themeSetter = (outerTheme: Theme) => + createMuiTheme(outerTheme, { + components: { + MuiLink: { + defaultProps: { + // @ts-ignore + component: LinkBehavior, + }, + }, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, + }, + }, + }); + +export default function LinkRouterWithTheme() { + return ( + :not(style) + :not(style)': { mt: 1 }, + }} + > + + + Link + + + + + ); +} diff --git a/docs/src/pages/guides/composition/ListRouter.js b/docs/src/pages/guides/routing/ListRouter.js similarity index 100% rename from docs/src/pages/guides/composition/ListRouter.js rename to docs/src/pages/guides/routing/ListRouter.js diff --git a/docs/src/pages/guides/composition/ListRouter.tsx b/docs/src/pages/guides/routing/ListRouter.tsx similarity index 100% rename from docs/src/pages/guides/composition/ListRouter.tsx rename to docs/src/pages/guides/routing/ListRouter.tsx diff --git a/docs/src/pages/guides/routing/routing.md b/docs/src/pages/guides/routing/routing.md new file mode 100644 index 00000000000000..9d69686619f0b0 --- /dev/null +++ b/docs/src/pages/guides/routing/routing.md @@ -0,0 +1,134 @@ +# Routing libraries + +

By default, the navigation is performed with a native <a> element. You can customize it to use your own router. For instance, using Next.js's Link or react-router.

+ +## Navigation components + +There are two main components available to perform navigations. +The most common one is the [`Link`](/components/link/) as its name might suggest. +It renders a native `` element and applies the `href` as an attribute. + +{{"demo": "pages/guides/routing/LinkDemo.js"}} + +You can also make a button perform navigation actions. +If your component is extending [`ButtonBase`](/api/button-base/), providing a `href` prop enables the link mode. +For instance, with a `Button` component: + +{{"demo": "pages/guides/routing/ButtonDemo.js"}} + +## Global theme Link + +In real-life applications, using a native `` element is rarely enough. +You can improve the user experience by using an enhanced Link component systematically. +The theme of Material-UI allows configuring this component once. +For instance, with react-router: + +```jsx +const LinkBehavior = React.forwardRef< + any, + Omit & { href: RouterLinkProps['to'] } +>((props, ref) => { + const { href, ...other } = props; + // Map href (Material-UI) -> to (react-router) + return ; +}); + +const theme = createMuiTheme({ + components: { + MuiLink: { + defaultProps: { + component: LinkBehavior, + }, + }, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, + }, + }, +}); +``` + +{{"demo": "pages/guides/routing/LinkRouterWithTheme.js", "defaultCodeOpen": false}} + +> ⚠️ This approach has limitations with TypeScript. +> The `href` prop only accepts a string. +> In the event you need to provide a richer structure, see the next section. + +## `component` prop + +You can achieve the integration with third-party routing libraries with the `component` prop. +You can learn more about this prop in the [composition guide](/guides/composition/#component-prop). + +Here are a few demos with [react-router](https://github.com/ReactTraining/react-router). +You can apply the same strategy with all the components (BottomNavigation, Card, etc.). + +### Link + +{{"demo": "pages/guides/routing/LinkRouter.js"}} + +### Button + +{{"demo": "pages/guides/routing/ButtonRouter.js"}} + +### List + +{{"demo": "pages/guides/routing/ListRouter.js"}} + +## More examples + +### Next.js + +Next.js has [a custom Link component](https://nextjs.org/docs/api-reference/next/link). +The [example folder](https://github.com/mui-org/material-ui/tree/HEAD/examples/nextjs-with-typescript) provides adapters for usage with Material-UI. + +- The first version of the adapter is the [`NextLinkComposed`](https://github.com/mui-org/material-ui/tree/HEAD/examples/nextjs-with-typescript/src/Link.tsx) component. + This component is unstyled and only responsible for handling the navigation. + The prop `href` was renamed `to` to avoid a naming conflict. + This is similar to react-router's Link component. + + ```tsx + import Button from '@material-ui/core/Button'; + import { NextLinkComposed } from '../src/Link'; + + export default function Index() { + return ( + + ); + } + ``` + +- The second version of the adapter is the `Link` component. + This component is styled. + It leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. + + ```tsx + import Link from '../src/Link'; + + export default function Index() { + return ( + + Link + + ); + } + ``` + +### Gatsby + +The [Link](https://www.gatsbyjs.com/docs/linking-between-pages/) component of Gatsby is built on `@reach/router`. +You can use the same previous documentation for react-router. +Unlike Next.js, it doesn't require to create an adapter. diff --git a/docs/src/pages/guides/typescript/typescript.md b/docs/src/pages/guides/typescript/typescript.md index 41e5045a60a254..764e5aa1a5db64 100644 --- a/docs/src/pages/guides/typescript/typescript.md +++ b/docs/src/pages/guides/typescript/typescript.md @@ -287,7 +287,7 @@ const theme = createMyTheme({ Many Material-UI components allow you to replace their root node via a `component` prop, this will be detailed in the component's API documentation. For example, a Button's root node can be replaced with a React Router's Link, and any additional props that are passed to Button, such as `to`, will be spread to the Link component. -For a code example concerning Button and react-router-dom checkout [these demos](/guides/composition/#routing-libraries). +For a code example concerning Button and react-router-dom checkout [these demos](/guides/routing/#component-prop). To be able to use props of such a Material-UI component on their own, props should be used with type arguments. Otherwise, the `component` prop will not be present in the props of the Material-UI component. diff --git a/docs/translations/api-docs/button-base/button-base.json b/docs/translations/api-docs/button-base/button-base.json index dff6172092c505..9a7b2316a02744 100644 --- a/docs/translations/api-docs/button-base/button-base.json +++ b/docs/translations/api-docs/button-base/button-base.json @@ -11,6 +11,7 @@ "disableTouchRipple": "If true, the touch ripple effect is disabled.", "focusRipple": "If true, the base button will have a keyboard focus ripple.", "focusVisibleClassName": "This prop can help identify which element has keyboard focus. The class name will be applied when the element gains the focus through keyboard interaction. It's a polyfill for the CSS :focus-visible selector. The rationale for using this feature is explained here. A polyfill can be used to apply a focus-visible class to other components if needed.", + "LinkComponent": "The component used to render a link when the href prop is provided.", "onFocusVisible": "Callback fired when the component is focused with a keyboard. We trigger a onFocus callback too.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "TouchRippleProps": "Props applied to the TouchRipple element." diff --git a/docs/translations/translations.json b/docs/translations/translations.json index ae30e831946f55..5786d09d6cea6c 100644 --- a/docs/translations/translations.json +++ b/docs/translations/translations.json @@ -296,6 +296,7 @@ "/guides/interoperability": "Style Library Interoperability", "/guides/minimizing-bundle-size": "Minimizing Bundle Size", "/guides/composition": "Composition", + "/guides/routing": "Routing", "/guides/server-rendering": "Server Rendering", "/guides/responsive-ui": "Responsive UI", "/guides/pickers-migration": "Migration from @material-ui/pickers", diff --git a/examples/nextjs-with-typescript/README.md b/examples/nextjs-with-typescript/README.md index 6731bfecd5de1f..d3aed748a67626 100644 --- a/examples/nextjs-with-typescript/README.md +++ b/examples/nextjs-with-typescript/README.md @@ -27,47 +27,5 @@ The project uses [Next.js](https://github.com/zeit/next.js), which is a framewor ## The link component Next.js has [a custom Link component](https://nextjs.org/docs/api-reference/next/link). -The example provides adapters for usage with Material-UI. - -- The first version of the adapter is the `NextLinkComposed` component. - This component is unstyled and only responsible for handling the navigation. - The prop `href` was renamed `to`. - - ```tsx - import Button from '@material-ui/core/Button'; - import { NextLinkComposed } from '../src/Link'; - - export default function Index() { - return ( - - ); - } - ``` - -- The second version of the adapter is the `Link` component. - This component is styled, it leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. - - ```tsx - import Link from '../src/Link'; - - export default function Index() { - return ( - - Link - - ); - } - ``` +The example folder provides adapters for usage with Material-UI. +More information [in the documentation](https://next.material-ui.com/guides/routing/#next-js). diff --git a/examples/nextjs/README.md b/examples/nextjs/README.md index bbf95025ae26db..d03e247066f495 100644 --- a/examples/nextjs/README.md +++ b/examples/nextjs/README.md @@ -27,47 +27,5 @@ The project uses [Next.js](https://github.com/zeit/next.js), which is a framewor ## The link component Next.js has [a custom Link component](https://nextjs.org/docs/api-reference/next/link). -The example provides adapters for usage with Material-UI. - -- The first version of the adapter is the `NextLinkComposed` component. - This component is unstyled and only responsible for handling the navigation. - The prop `href` was renamed `to`. - - ```tsx - import Button from '@material-ui/core/Button'; - import { NextLinkComposed } from '../src/Link'; - - export default function Index() { - return ( - - ); - } - ``` - -- The second version of the adapter is the `Link` component. - This component is styled, it leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. - - ```tsx - import Link from '../src/Link'; - - export default function Index() { - return ( - - Link - - ); - } - ``` +The example folder provides adapters for usage with Material-UI. +More information [in the documentation](https://next.material-ui.com/guides/routing/#next-js). diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts index 0f50cee128f328..e0c6fecb2ef8d8 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts +++ b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts @@ -71,6 +71,11 @@ export interface ButtonBaseTypeMap

', () => { expect(button).to.have.attribute('href', 'https://google.com'); }); + it('should use custom LinkComponent when provided in the theme', () => { + const CustomLink = React.forwardRef((props, ref) => { + return ( + + {props.children} + + ); + }); + const theme = createMuiTheme({ + components: { + MuiButtonBase: { + defaultProps: { + LinkComponent: CustomLink, + }, + }, + }, + }); + + const { container, getByTestId } = render( + + Hello + , + ); + const button = container.firstChild; + expect(getByTestId('customLink')).not.to.equal(null); + expect(button).to.have.property('nodeName', 'A'); + expect(button).to.have.attribute('href', 'https://google.com'); + }); + it('applies role="button" when an anchor is used without href', () => { const { getByRole } = render(Hello); const button = getByRole('button'); diff --git a/test/docs-regressions-before.png b/test/docs-regressions-before.png index 2cab5396d5d2da..d1e7f17a11b2ed 100644 Binary files a/test/docs-regressions-before.png and b/test/docs-regressions-before.png differ diff --git a/test/docs-regressions-diff.png b/test/docs-regressions-diff.png index d6d602f16e732c..f6849065128a8f 100644 Binary files a/test/docs-regressions-diff.png and b/test/docs-regressions-diff.png differ