Repository: mui/material-ui (TypeScript)
Date: 2022-07-23 20:03:05+00:00
Task type: Bug Fix

Issue:
Link with `component=button` does not use custom font
### Duplicates

- [X] I have searched the existing issues

### Latest version

- [X] I have tested the latest version

### Current behavior 😯

When adding a custom font all components work well (like Typography Link and Button)
But when using `<Link component="button">Hi</Link>` it uses default font



### Expected behavior 🤔

`Link` should always use the custom font 

### Steps to reproduce 🕹

https://codesandbox.io/s/distracted-wind-jjxdxm?file=/src/Demo.tsx

```jsx
import { Link, createTheme, CssBaseline, ThemeProvider } from "@mui/material";

const theme = createTheme({
  typography: {
    fontFamily: "Inconsolata, Arial"
  }
});

export default function Demo() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Link>This is good (it's Inconsolata)</Link>
      <br />
      <Link component="button">This is not good (it's Ariel)</Link>
    </ThemeProvider>
  );
}
```

### Context 🔦

_No response_

### Your environment 🌎

Material UI v5.11.0
Link with `component=button` does not use custom font
### Duplicates

- [X] I have searched the existing issues

### Latest version

- [X] I have tested the latest version

### Current behavior 😯

When adding a custom font all components work well (like Typography Link and Button)
But when using `<Link component="button">Hi</Link>` it uses default font



### Expected behavior 🤔

`Link` should always use the custom font 

### Steps to reproduce 🕹

https://codesandbox.io/s/distracted-wind-jjxdxm?file=/src/Demo.tsx

```jsx
import { Link, createTheme, CssBaseline, ThemeProvider } from "@mui/material";

const theme = createTheme({
  typography: {
    fontFamily: "Inconsolata, Arial"
  }
});

export default function Demo() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Link>This is good (it's Inconsolata)</Link>
      <br />
      <Link component="button">This is not good (it's Ariel)</Link>
    </ThemeProvider>
  );
}
```

### Context 🔦

_No response_

### Your environment 🌎

Material UI v5.11.0


Issue discussion:
The problem here is that the Link component does not explicitly set its `font-family` but inherits the one from the parent element. This way it uses the same style as the surrounding text and can be placed in headers, paragraphs, etc. without any changes.
When you supply a `button` to the component prop, this style inheritance is broken, as, by default, buttons have a font-family set by the browser.
You can work around this issue by setting a style that will make the button's font properties inherit from its parent, such as:

```css
.MuiLink-button {
  font-family: inherit;
}
```

I'm not keen on setting this in the library at this point, as this can cause an unexpected change of fonts in many applications.
From my perspective, it's a support question. We document this here: https://mui.com/material-ui/react-link/

<img width="781" alt="Screenshot 2022-06-22 at 14 27 17" src="https://user-images.githubusercontent.com/3165635/175028719-e9415a79-fbea-48a0-9d87-9674e1961f89.png">

It was designed so the correct approach is: 

```tsx
<Link component="button" variant="body1">This is not good (it's Ariel)</Link>
```

https://codesandbox.io/s/elegant-cray-zv1x60?file=/src/Demo.tsx

<img width="284" alt="Screenshot 2022-06-22 at 14 28 05" src="https://user-images.githubusercontent.com/3165635/175028841-d38aae39-ecdf-4321-a31d-60652e40f7a0.png">
However, there is a broader question (not directly surfaced in this issue that Michal raised), we say variant: "inherit", but it doesn't truly inherit:

```jsx
export default function Demo() {
  return (
    <ThemeProvider theme={theme}>
      <Typography variant="body1">
        <CssBaseline />

        <Link>This is good (it's Inconsolata)</Link>
        <br />
        <Link component="button">This is not good (it's Ariel)</Link>
      </Typography>
    </ThemeProvider>
  );
}
```

<img width="271" alt="Screenshot 2022-06-22 at 14 30 25" src="https://user-images.githubusercontent.com/3165635/175029320-99edfffa-01fd-47a2-84fc-43e306a1bd32.png">

https://codesandbox.io/s/xenodochial-stitch-wpjcqk?file=/src/Demo.tsx

We could fix this 👍 
I'm happy to accept a PR for this issue.
The problem here is that the Link component does not explicitly set its `font-family` but inherits the one from the parent element. This way it uses the same style as the surrounding text and can be placed in headers, paragraphs, etc. without any changes.
When you supply a `button` to the component prop, this style inheritance is broken, as, by default, buttons have a font-family set by the browser.
You can work around this issue by setting a style that will make the button's font properties inherit from its parent, such as:

```css
.MuiLink-button {
  font-family: inherit;
}
```

I'm not keen on setting this in the library at this point, as this can cause an unexpected change of fonts in many applications.
From my perspective, it's a support question. We document this here: https://mui.com/material-ui/react-link/

<img width="781" alt="Screenshot 2022-06-22 at 14 27 17" src="https://user-images.githubusercontent.com/3165635/175028719-e9415a79-fbea-48a0-9d87-9674e1961f89.png">

It was designed so the correct approach is: 

```tsx
<Link component="button" variant="body1">This is not good (it's Ariel)</Link>
```

https://codesandbox.io/s/elegant-cray-zv1x60?file=/src/Demo.tsx

<img width="284" alt="Screenshot 2022-06-22 at 14 28 05" src="https://user-images.githubusercontent.com/3165635/175028841-d38aae39-ecdf-4321-a31d-60652e40f7a0.png">
However, there is a broader question (not directly surfaced in this issue that Michal raised), we say variant: "inherit", but it doesn't truly inherit:

```jsx
export default function Demo() {
  return (
    <ThemeProvider theme={theme}>
      <Typography variant="body1">
        <CssBaseline />

        <Link>This is good (it's Inconsolata)</Link>
        <br />
        <Link component="button">This is not good (it's Ariel)</Link>
      </Typography>
    </ThemeProvider>
  );
}
```

<img width="271" alt="Screenshot 2022-06-22 at 14 30 25" src="https://user-images.githubusercontent.com/3165635/175029320-99edfffa-01fd-47a2-84fc-43e306a1bd32.png">

https://codesandbox.io/s/xenodochial-stitch-wpjcqk?file=/src/Demo.tsx

We could fix this 👍 
I'm happy to accept a PR for this issue.

Solution patch:
diff --git a/packages/mui-material/src/styles/createTypography.js b/packages/mui-material/src/styles/createTypography.js
--- a/packages/mui-material/src/styles/createTypography.js
+++ b/packages/mui-material/src/styles/createTypography.js
@@ -72,6 +72,13 @@ export default function createTypography(palette, typography) {
     button: buildVariant(fontWeightMedium, 14, 1.75, 0.4, caseAllCaps),
     caption: buildVariant(fontWeightRegular, 12, 1.66, 0.4),
     overline: buildVariant(fontWeightRegular, 12, 2.66, 1, caseAllCaps),
+    inherit: {
+      fontFamily: 'inherit',
+      fontWeight: 'inherit',
+      fontSize: 'inherit',
+      lineHeight: 'inherit',
+      letterSpacing: 'inherit',
+    },
   };
 
   return deepmerge(
diff --git a/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js b/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js
--- a/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js
+++ b/packages/mui-system/src/styleFunctionSx/defaultSxConfig.js
@@ -1,9 +1,42 @@
+import { unstable_capitalize as capitalize } from '@mui/utils';
 import { padding, margin } from '../spacing';
+import { handleBreakpoints } from '../breakpoints';
 import { borderRadius, borderTransform } from '../borders';
 import { gap, rowGap, columnGap } from '../cssGrid';
 import { paletteTransform } from '../palette';
 import { maxWidth, sizingTransform } from '../sizing';
 
+const createFontStyleFunction = (prop) => {
+  return (props) => {
+    if (props[prop] !== undefined && props[prop] !== null) {
+      const styleFromPropValue = (propValue) => {
+        let value =
+          props.theme.typography?.[
+            `${prop}${
+              props[prop] === 'default' || props[prop] === prop
+                ? ''
+                : capitalize(props[prop]?.toString())
+            }`
+          ];
+
+        if (!value) {
+          value = props.theme.typography?.[propValue]?.[prop];
+        }
+
+        if (!value) {
+          value = propValue;
+        }
+
+        return {
+          [prop]: value,
+        };
+      };
+      return handleBreakpoints(props, props[prop], styleFromPropValue);
+    }
+    return null;
+  };
+};
+
 const defaultSxConfig = {
   // borders
   border: {
@@ -283,15 +316,18 @@ const defaultSxConfig = {
   // typography
   fontFamily: {
     themeKey: 'typography',
+    style: createFontStyleFunction('fontFamily'),
   },
   fontSize: {
     themeKey: 'typography',
+    style: createFontStyleFunction('fontSize'),
   },
   fontStyle: {
     themeKey: 'typography',
   },
   fontWeight: {
     themeKey: 'typography',
+    style: createFontStyleFunction('fontWeight'),
   },
   letterSpacing: {},
   textTransform: {},


Test patch:
diff --git a/packages/mui-material/src/styles/CssVarsProvider.test.js b/packages/mui-material/src/styles/CssVarsProvider.test.js
--- a/packages/mui-material/src/styles/CssVarsProvider.test.js
+++ b/packages/mui-material/src/styles/CssVarsProvider.test.js
@@ -246,7 +246,7 @@ describe('[Material UI] CssVarsProvider', () => {
       );
 
       expect(container.firstChild?.textContent).to.equal(
-        'htmlFontSize,pxToRem,fontFamily,fontSize,fontWeightLight,fontWeightRegular,fontWeightMedium,fontWeightBold,h1,h2,h3,h4,h5,h6,subtitle1,subtitle2,body1,body2,button,caption,overline',
+        'htmlFontSize,pxToRem,fontFamily,fontSize,fontWeightLight,fontWeightRegular,fontWeightMedium,fontWeightBold,h1,h2,h3,h4,h5,h6,subtitle1,subtitle2,body1,body2,button,caption,overline,inherit',
       );
     });
   });
diff --git a/packages/mui-material/src/styles/createTypography.test.js b/packages/mui-material/src/styles/createTypography.test.js
--- a/packages/mui-material/src/styles/createTypography.test.js
+++ b/packages/mui-material/src/styles/createTypography.test.js
@@ -74,6 +74,15 @@ describe('createTypography', () => {
     );
   });
 
+  it('should apply font CSS properties to inherit variant', () => {
+    const typography = createTypography(palette, {});
+    const fontProperties = ['fontFamily', 'fontWeight', 'fontSize', 'lineHeight', 'letterSpacing'];
+
+    fontProperties.forEach((prop) => {
+      expect(typography.inherit[prop]).to.equal('inherit');
+    });
+  });
+
   describe('warnings', () => {
     it('logs an error if `fontSize` is not of type number', () => {
       expect(() => {
diff --git a/packages/mui-system/src/styleFunctionSx/styleFunctionSx.test.js b/packages/mui-system/src/styleFunctionSx/styleFunctionSx.test.js
--- a/packages/mui-system/src/styleFunctionSx/styleFunctionSx.test.js
+++ b/packages/mui-system/src/styleFunctionSx/styleFunctionSx.test.js
@@ -1,5 +1,6 @@
 import { expect } from 'chai';
 import createMixins from '@mui/material/styles/createMixins';
+import createTypography from '@mui/material/styles/createTypography';
 import createBreakpoints from '../createTheme/createBreakpoints';
 import styleFunctionSx from './styleFunctionSx';
 
@@ -419,4 +420,25 @@ describe('styleFunctionSx', () => {
       ).not.to.throw();
     });
   });
+
+  it('resolves inherit typography properties', () => {
+    const result = styleFunctionSx({
+      theme: { typography: createTypography({}, {}) },
+      sx: {
+        fontFamily: 'inherit',
+        fontWeight: 'inherit',
+        fontSize: 'inherit',
+        lineHeight: 'inherit',
+        letterSpacing: 'inherit',
+      },
+    });
+
+    expect(result).deep.equal({
+      fontFamily: 'inherit',
+      fontWeight: 'inherit',
+      fontSize: 'inherit',
+      lineHeight: 'inherit',
+      letterSpacing: 'inherit',
+    });
+  });
 });