Responsive Typography in MUI? - reactjs

Designs commonly have smaller headline fonts for mobile designs.
Does MUI have a mechanism for making the typography responsive?
I see that the default theme has the font sizes defined in rems - does that mean it's a matter of just reducing the base font-size? (That doesn't seem to work, what if you want to reduce the headline fonts at different rates).

Update
MUI v4 has responsive typography built in! Check here for details.
Old response
#Luke's answer is great. I wanted to add some detail to make this work in practice, because both breakpoints and pxToRem are accessible on the theme object... making this becomes a chicken and egg problem! My approach:
import { createMuiTheme } from "#material-ui/core"
const defaultTheme = createMuiTheme({ ... customisations that don’t rely on theme properties... })
const { breakpoints, typography: { pxToRem } } = defaultTheme
const theme = {
...defaultTheme,
overrides: {
MuiTypography: {
h1: {
fontSize: "5rem",
[breakpoints.down("xs")]: {
fontSize: "3rem"
}
}
}
}
}
export default theme

None of the other answers uses the variant preset.
The best way to MUI v5, and use variant:
<Typography sx={{ typography: { sm: 'body1', xs: 'body2' } }} >
Hello world!
</Typography>

Update
The latest version of Material UI (v4) fully supports response typography. See the official documentation for details.
Original Answer
As of version 1.x, Material UI does not have a specific mechanism for handling responsive typography.
You can scale the size of all MUI Typography by changing the font-size of the <html> element, as you mentioned. (docs)
const styles = theme => ({
"#global": {
html: {
[theme.breakpoints.up("sm")]: {
fontSize: 18
}
}
}
}
Theme overrides
As far as i know, the only other option is to use theme overrides to define custom styles for each of the Typography variants.
This requires replicating some of the logic in createTypography.js (ie setting line heights to maintain vertical rhythm)
const theme = createMuiTheme({
overrides: {
MuiTypography: {
headline: {
fontSize: pxToRem(24),
[breakpoints.up("md")]: {
fontSize: pxToRem(32)
}
}
}
}

As described in the docs you can use the responsiveFontSizes() helper to make Typography font sizes in the theme responsive.
import { createMuiTheme, responsiveFontSizes } from '#material-ui/core/styles';
let theme = createMuiTheme();
theme = responsiveFontSizes(theme);

MUI v5 adds sx prop to all MUI components which supports responsive values where you can pass an object to define the values at different breakpoints:
<Typography
sx={{
fontSize: {
lg: 30,
md: 20,
sm: 15,
xs: 10
}
}}
>
This text is resized on different screen breakpoints
</Typography>
Similar to Box, Typography also supports system properties so you can skip the sx prop and pass the fontSize property directly. The code below is the same as above, just a bit shorter to write:
<Typography
fontSize={{
lg: 30,
md: 20,
sm: 15,
xs: 10
}}
>
This text is resized on different screen breakpoints
</Typography>

My approach with v5
import { createTheme } from "#mui/material";
let theme = createTheme({
// ...
});
theme = createTheme(theme, {
typography: {
h1: {
fontSize: 53,
[theme.breakpoints.only("sm")]: {
fontSize: 71,
},
},
},
});
export default theme;

This seem to be working for me v5
in App.js
...
import {
createTheme,
responsiveFontSizes,
ThemeProvider,
} from '#mui/material/styles';
let theme = createTheme();
theme = responsiveFontSizes(theme);
...
function App() {
return (
<ThemeProvider theme={theme}>
<Router>
.....
</Router>
</ThemeProvider>
);
}
"To automate this setup, you can use the responsiveFontSizes() helper to make Typography font sizes in the theme responsive."
https://mui.com/customization/typography/#responsive-font-sizes

Related

How to style Input in material ui

I am new to material ui.
I use fifth version.
<InputBase
ref={params.InputProps.ref}
inputProps={params.inputProps}
autoFocus
sx={{
...InputCSS,
}}
/>
const InputCSS = {
width: '100%',
textIndent: '17px',
py: '12px',
fontSize: '20px',
borderRadius: '3px',
border: '1.5px solid rgba(0, 0, 0, 0.4)',
'MuiInputBase-root': { // does not work
borderColor: 'red !important',
color: 'red !important',
},
'&:focus' : { // does not work
...
}
}
I could have used styled('input') and it works, I can set &:focus and it works but I can't type anything in the input.
I want to get rid of the initial border and set focus property.
How can I change the border for this class?
I know that in v5 we can style our components using variants or sx or styled.
What is the best advice for styling mui components? Because almost all the info in the internet uses outdated useStyle or makeStyles which doesn't work with react 18v.
sometimes I just struggle with components styling in mui
You have several ways to customize a Mui component, but my three favorite approaches are:
Styled utility
Sx prop
Custom global theme
So when should I use each of these approaches?
Styled utility
If you want to make a component reusable across your app, go with styled, if you had ever used styled components then styled will be very familiar to you, here is an example of how to use it:
import * as React from 'react';
import Slider, { SliderProps } from '#mui/material/Slider';
import { alpha, styled } from '#mui/material/styles';
// if you are using typescript, don't forget to pass the component props on styled
const SuccessSlider = styled(Slider)<SliderProps>(({ theme }) => ({
width: 300,
color: theme.palette.success.main,
// to override the styles of inner elements,
// you have to use the & selector followed by the class name.
'&.MuiSlider-thumb': {
'&:hover, &.Mui-focusVisible': {
boxShadow: `0px 0px 0px 8px ${alpha(theme.palette.success.main, 0.16)}`,
},
'&.Mui-active': {
boxShadow: `0px 0px 0px 14px ${alpha(theme.palette.success.main, 0.16)}`,
},
},
}));
export default function StyledCustomization() {
return <SuccessSlider defaultValue={30} />;
}
To make the component even more dynamically, you can define custom props as well, like width, color, border and so on, read the styled docs to know more about it.
Sx prop
If you want to make an one time off style in a single component, the easiest way is to use the sx prop, but be careful with this approach because it can lead to a lot of repetition in your code. Following the code you gave:
<InputBase
ref={params.InputProps.ref}
inputProps={params.inputProps}
autoFocus
sx={{
...InputCSS,
}}
/>
const InputCSS = {
width: '100%',
textIndent: '17px',
py: '12px',
fontSize: '20px',
borderRadius: '3px',
border: '1.5px solid rgba(0, 0, 0, 0.4)',
// you should pass the & selector followed by the class that you want to override
'&.MuiInputBase-root': {
// avoid the use of !important
borderColor: 'red',
color: 'red',
},
'&.MuiInputBase-root:focus': {
...
}
}
check it out on codeSandbox. Just a suggestion, depending on your case the component TextField could fit better as it comes with some good styles and you don't need to style it from scratch.
Side note:
Every mui component has an api doc with a css section where you can find all available classes to override, for instance, see the InputBase api docs, also read the docs about sx prop.
Custom theme
At last but not least, if you want to customize your whole app with custom palette, components, typography, breakpoints and so on, no doubt you should use a custom theme, as mui provides a powerful tool called createTheme to do so, what I like the most in custom theme is the possibility to make custom variants of the component, like so:
import * as React from "react";
import { createTheme, ThemeProvider } from "#mui/material/styles";
import Button from "#mui/material/Button";
import { red } from "#mui/material/colors";
// if you are using typescript, you must declare the module with the
// custom properties in order to get access of this property when using the component
declare module "#mui/material/Button" {
// define custom variants
interface ButtonPropsVariantOverrides {
dashed: true;
redVariant: true;
}
}
const defaultTheme = createTheme();
const theme = createTheme({
components: {
MuiButton: {
variants: [
{
// use the variant name defined earlier
props: { variant: "dashed" },
// set the styles for this variant
style: {
textTransform: "none",
border: `2px dashed ${defaultTheme.palette.primary.main}`,
color: defaultTheme.palette.primary.main
}
},
{
props: { variant: "redVariant" },
style: {
border: `2px solid ${red[300]}`,
color: red[600]
}
}
]
}
}
});
export default function GlobalThemeVariants() {
return (
// use the theme provider to get access of custom theme
// and variants within any child component
<ThemeProvider theme={theme}>
<Button variant="dashed" sx={{ m: 1 }}>
Dashed
</Button>
<Button variant="redVariant" color="secondary">
custom red variant
</Button>
</ThemeProvider>
);
}
See the example, also take a look at the custom theme docs. Hope I clarified the things a bit!

Passing custom themes into withStyles

I have created a theme that I'm trying to call in my useStyles. This is the theme
import { createMuiTheme } from "#material-ui/core/styles";
const customTheme = createMuiTheme({
palette: {
primary: {
main: "#00ffff"
},
secondary: {
light: "#214b63",
main: "#000000",
dark: "#00660f",
contrastText: "#fff"
}
}
});
export default customTheme;
I want to use the secondary color as part of the override:
import React from "react";
import { Grid, Typography } from "#material-ui/core";
import { withStyles, MuiThemeProvider } from "#material-ui/core/styles";
import customTheme from "./newTheme";
const useStyles = (theme) => ({
root: {
color: theme.palette.secondary.main
},
grid: {
height: "100vh"
}
});
class CustomThemes extends React.Component {
render() {
const { classes } = this.props;
return (
<MuiThemeProvider theme={customTheme}>
<Grid
className={classes.grid}
container
justify="center"
alignItems="center"
>
<Grid item>
<Typography className={classes.root}>
Upgraded to withStyles theming problem
</Typography>
</Grid>
</Grid>
</MuiThemeProvider>
);
}
}
export default withStyles(useStyles)(CustomThemes);
I'm trying to pass the theme colors into the useStyles, so that the root color can work. Is there any way for me to pass the theme color into my override? I read that there is a way with makeStyles, but all my components are class-based, and converting all of them into hooks would not be possible. I need this because I have a similar component being used at multiple places. It would be convenient to be able to control the color palettes from one place.
I have tried doing it in this manner as well, but this doesn't take in the custom theme.:
const useStyles = (customTheme) => ({
root: {
color: customTheme.palette.secondary.main
},
grid: {
height: "100vh"
}
});
Another way I've tried is
export default withStyles(useStyles, { withTheme: true })(CustomThemes);
I have a css injection as well, but wanted to know it can be done this way (what I believe is the native-to-mui way). Appreciate all the help!
Found the answer. Didn't know this, but I can call the theme directly into my useStyles:
const useStyles = (theme) => ({
root: {
color: customTheme.palette.secondary.main
},
grid: {
height: "100vh"
}
});
If anyone knows why I don't need to inject the theme directly in, would greatly help in understanding why this works. I spent almost 2 days trying to pass the theme in.

How to Change Light and Dark Theme Colors for Material-UI AppBar?

I'm not very deep into React yet...
The AppBar is styled like a button which i don't like.
So I want to change it's colors but also have it working switching light and dark scheme.
[Edit]
I want to define own colors for AppBar (without changing present colors) und add them to light/dark theme respectively so it's changing automatically to light/dark when i switch themes.
[/Edit]
Changing colors with ThemeProvider is already not working:
const theme = createMuiTheme({
palette: {
// type: 'dark'
},
overrides: {
MuiTypography: {
h1: {
fontSize: 24,
fontWeight: "normal"
},
h2: {
fontSize: 22,
fontWeight: "normal"
},
},
MuiAppBar: {
background: 'white',
borderBottom: "1px solid lightGray",
}
},
MuiTypography works, though.
(As I see here https://material-ui.com/customization/default-theme/ there's no AppBar only Typography.)
How can I tell AppBar to use other colors than primary/secondary while staying synced with the built-in light-dark-theme mechanic?
Ciao, if you want to switch theme (from dark theme to light theme for example) you could use primary and secondary colors (previously defined in theme object).
So lets take this codesandbox example I made:
I defined 2 colors in theme:
const Theme = {
palette: {
primary: {
main: "#000000"
},
secondary: {
main: "#FFFFFF"
}
}
};
In this case, primary is our dark theme and secondary is the light theme.
I created MUI theme:
const theme = createMuiTheme(Theme);
I wrapped the AppBar component into a ThemeProvider with the theme created:
<ThemeProvider theme={theme}>
<AppBar position="static" color={themeSelected}>
....
</AppBar>
</ThemeProvider>
As you can see on AppBar component, I putted a state variable in color props (themeSelected).
Well now I created just a simple IconButton with an SwapHoriz icon , and on click I change my state variable themeSelected:
...
const [themeSelected, setThemeSelected] = useState("primary"); // init as primary color
...
const changeTheme = () => { // function to set state
if (themeSelected === "primary") setThemeSelected("secondary");
else setThemeSelected("primary");
};
...
<IconButton //icon button with onClick handler
className={classes.menuButton}
color="inherit"
aria-label="open drawer"
onClick={() => {
changeTheme();
}}
>
<SwapHoriz />
</IconButton>
Thats it. Now if you click SwapHoriz you can change your color theme:
Primary color theme
Secondary color theme
EDIT
After you explanation, I understood that you want distinct colors for AppBar and, when you change theme, AppBar should take that colors.
In this case the only way I know is to override the classes of AppBar in this way:
<AppBar
position="static"
color={themeSelected}
classes={{
colorPrimary: classes.appbarpalette,
colorSecondary: classes.appbarpalette
}}
>
Then in your makeStyles:
...
appbarpalette: {
"&.MuiAppBar-colorPrimary": {
backgroundColor: purple[600] // instead of #000000 for primary now you have purple
},
"&.MuiAppBar-colorSecondary": {
backgroundColor: green[600] // instead of #FFFFFF for secondary now you have green
}
}
I updated my codesandbox example.

Material-UI custom theming

I want to create a custom theme and customize some Material-UI components. I followed this customization tutorial provided by Material-UI. With this, I was able to do the following:
Creating costume theme:
//MUI THEMING
import {
createMuiTheme,
makeStyles,
ThemeProvider,
} from "#material-ui/core/styles";
import Theme from "./../../theme";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: Theme.palette.primary.main,
},
}));
const theme = createMuiTheme({
normal: {
primary: Theme.palette.primary.main,
secondary: Theme.palette.secondary.main,
},
});
Using costume theme:
<ThemeProvider theme={theme}>
<AppBar
position="static"
classes={{
root: classes.root,
}}>
...
</AppBar>
</ThemeProvider>
As expected, this resulted in a costume colored AppBar:
However, when I tried the same with bottom navigation, -trying to change the default primary color-, I could not get it to work. I figured that based on the tutorial, I have to use "&$selected": in the create them to get it to work, but even with this my best result was something like this:
How do I change the primary color of Bottom Navigation with no label?
Sidenote: While I was searching for the solution, I stumbled on the default theme ovject. How can I access this, how can I overwrite it?
In my project, I create a global MUI theme to override the default theme. In makeStyle you can pass a param theme in the callback function like this to get the whole MUI theme object:
const useStyles = makeStyles(theme => {
console.log(theme) // print mui global theme object
return {...your classes here}
})
After that, copy this object to a new file like muiTheme.js to create your own theme. Change these values in this object that you want to override.
// muiTheme.js
import { createMuiTheme } from '#material-ui/core/styles'
const theme = createMuiTheme({
breakpoints: {
keys: ['xs', 'sm', 'md', 'lg', 'xl'],
values: {
xs: 0,
sm: 600,
md: 960,
lg: 1280,
xl: 1920,
},
},
...
})
export default theme
Then, in index.js, use ThemeProvider to override MUI's theme.
import { ThemeProvider } from '#material-ui/core/styles'
import muiTheme from './theme/muiTheme'
import App from './App'
const Root = () => (
<BrowserRouter>
<ThemeProvider theme={muiTheme}>
<App />
</ThemeProvider>
</BrowserRouter>
)
ReactDOM.render(<Root />, document.getElementById('root'))

Set Typography text color in MUI

I'm pretty new to MUI, and I'm trying to set a Typography with a text color like this:
const theme = createMuiTheme({
palette: {
text:{
primary: "#FFFFFF"
}
}
});
const WhiteText = (props: { text:string, varient: Variant | 'inherit'}) => {
return <ThemeProvider theme={theme}>
<Typography variant={props.varient} align="center" color="textPrimary">{props.text}</Typography>
</ThemeProvider>
}
...
<WhiteText varient="h3" text="This text should be white"/>
but the text will not change color :/
Am I applying the theme wrong?
Though your approach works fine in this sandbox, it is not the approach I would recommend. Instead of nested themes, for customizations like this I would recommend using withStyles as shown below (for v4 of Material-UI -- v5 example further down).
import React from "react";
import { withStyles } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
const WhiteTextTypography = withStyles({
root: {
color: "#FFFFFF"
}
})(Typography);
export default function App() {
return (
<div className="App" style={{ backgroundColor: "black" }}>
<WhiteTextTypography variant="h3">
This text should be white
</WhiteTextTypography>
</div>
);
}
In v5, MUI has enhanced the color prop significantly (for all components that have a color prop) to support any color in the theme's palette, so for white you can use common.white:
import React from "react";
import Typography from "#mui/material/Typography";
export default function App() {
return (
<div className="App" style={{ backgroundColor: "black" }}>
<Typography variant="h3" color="common.white">
This text should be white
</Typography>
</div>
);
}
Related answer: Can you add an additional color in Material UI?
If you want to set a default color for all Typography elements, but not for other Material UI elements you can try this:
const theme = createMuiTheme({
typography: {
allVariants: {
color: "pink"
},
},
});
If you don't want to use any themes. You can set it via style Attribute also.
<Typography style={{color:"#00adb5"}} variant="h3" >My Text</Typography>
For MUI 5, use sx attribute,
<Typography sx={{ color: "#00adb5" }} variant="h3">
My Text
</Typography>
The color prop of Typography is theme aware which is a nice feature of sx prop. This means besides setting the color as usual like this:
<Typography variant="h1" color="#00ff00">
You can reference the themed colors, either from the default palette or a custom palette defined like below:
const theme = createTheme({
palette: {
tomato: '#FF6347',
pink: {
deep: '#FF1493',
hot: '#FF69B4',
medium: '#C71585',
pale: '#DB7093',
light: '#FFB6C1',
},
},
});
After registering the custom theme in ThemeProvider, you can use it in Typography by specifying the string path of the Palette object to the color value:
<Typography color="tomato">text</Typography>
<Typography color="pink.deep">text</Typography>
<Typography color="pink.hot">text</Typography>
<Typography color="pink.medium">text</Typography>
<Typography color="pink.pale">text</Typography>
<Typography color="pink.light">text</Typography>
Here is a couple of examples of Typograhy using the default colors from the palette:
<Typography color="primary.main">text</Typography>
<Typography color="primary.dark">text</Typography>
<Typography color="primary.light">text</Typography>
<Typography color="secondary">text</Typography>
<Typography color="text.secondary">text</Typography>
<Typography color="text.disabled">text</Typography>
Set Typography Text Color in Material UI
<Typography gutterBottom variant="h9" component="h2" color="secondary">
{card.unitNumberList}
</Typography>
I would try this -
Include a typgraphy property in your theme, something like below with an 'h3' variant.
const theme = createMuiTheme({
palette: {
text: {
primary: "#FFFFFF"
}
},
typography: {
useNextVariants: true,
fontFamily: "Montserrat",
h3: {
fontSize: 33,
fontFamily: "Montserrat",
fontWeight: 300,
color: "#2882F8",
letterSpacing: "0.0075em",
verticalAlign: "middle",
alignItems: "center",
textAlign: "center"
}
}
});
Then the color of your Typography should come directly from the variant="h3" that you just declared inside theme. You dont need to seperately pass the 'color' props to Typgraphy
For a working implementations of this, you can check this Repo of mine, where I am keeping all my Typography variants in a single central global file called globalTheme.js and in the App.js wrapping all the other components within MuiThemeProvider as below
<MuiThemeProvider theme={globalTheme}>
So all Typography component anywhere in the project will have access to the variants that I have declared in that globalTheme.js file.
First of all, you need to define alternative colors for the text elements.
text: {
primary: 'rgba(60, 72, 88, 1)',
secondary: 'rgba(132, 146, 166, 1)',
disabled: 'rgba(60, 72, 88, 0.38)',
hint: 'rgba(60, 72, 88, 0.38)',
}
Then you can do the following:
<Typography variant="h1">Lorem ipsum</Typography> // Default text color
<Typography variant="subtitle1" color="textSecondary">dolor sit amet</Typography> // Secondary text color.
<Typography variant="body1" color="secondary">consectetur adipiscing elit</Typography> // Global secondary color.
You can try using make styles from the material-ui core to create a custom look for your text which can include the text colour as shown in the example below
import {makeStyles} from '#material-ui/core/styles'
const useStyles=makeStyles((theme)=>({
text:{
color:"#ffffff"
}
}));
const classes=useStyles();
<Typography align="center" className={classes.text}>This text should be white</Typography>
For those who are still on v4, uses typescript and want to have a typesafe definition can extend mui's Typography like this:
import React, { FC } from "react";
import { createStyles, makeStyles, Theme } from "#material-ui/core";
import MuiTypography, { TypographyProps } from "#material-ui/core/Typography";
import clsx from "clsx";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
warning: {
color: theme.palette.warning.main,
},
success: {
color: theme.palette.success.main,
},
})
);
type AdditionalColorKeys = keyof ReturnType<typeof useStyles>;
export type TypographyWithSpacingProps = Omit<TypographyProps, "color"> & {
color?: AdditionalColorKeys | TypographyProps["color"];
};
export const Typography: FC<TypographyWithSpacingProps> = ({ color, className, ...props }) => {
const classes = useStyles();
let colorClass = "";
if (color && color in classes) {
colorClass = classes[color as keyof ReturnType<typeof useStyles>];
}
return <MuiTypography {...props} className={clsx(className, colorClass)} />;
};
You can also simply change the Typography's color by adding system props 'sx'
like this
<Typography
variant="h6"
sx={{
color: "white",
}}
>

Resources