Skip to main content

styled() API

The styled() utility lets you create custom styled components with access to the theme.

Basic Usage

import { styled } from '@mui/system';

const StyledDiv = styled('div')({
  backgroundColor: 'blue',
  padding: '8px',
});

function App() {
  return <StyledDiv>Styled content</StyledDiv>;
}

API Signature

function styled(
  tag: React.ElementType,
  options?: {
    name?: string,
    slot?: string,
    skipVariantsResolver?: boolean,
    skipSx?: boolean,
    overridesResolver?: (
      props: any,
      styles: Record<string, any>
    ) => any,
    shouldForwardProp?: (prop: string) => boolean,
  }
): StyledComponent

Parameters

  • tag - The component or HTML element to style
  • options - Optional configuration object
    • name - Component name for theme overrides
    • slot - Slot name for component parts
    • skipVariantsResolver - Skip theme variants (default: false)
    • skipSx - Skip sx prop processing (default: false)
    • shouldForwardProp - Determine which props to forward to DOM
    • overridesResolver - Resolve theme style overrides

Source Implementation

From createStyled.js:132-307:
const styled = (tag, inputOptions = {}) => {
  const {
    name: componentName,
    slot: componentSlot,
    skipVariantsResolver: inputSkipVariantsResolver,
    skipSx: inputSkipSx,
    overridesResolver = defaultOverridesResolver(lowercaseFirstLetter(componentSlot)),
    ...options
  } = inputOptions;

  const skipVariantsResolver =
    inputSkipVariantsResolver !== undefined
      ? inputSkipVariantsResolver
      : (componentSlot && componentSlot !== 'Root' && componentSlot !== 'root') || false;

  const skipSx = inputSkipSx || false;

  // ... implementation
};

Using with Theme

Access theme values in your styles:
import { styled } from '@mui/system';

const Card = styled('div')(({ theme }) => ({
  backgroundColor: theme.palette.background.paper,
  padding: theme.spacing(2),
  borderRadius: theme.shape.borderRadius,
  boxShadow: theme.shadows[2],
}));

Dynamic Styles with Props

Use props to create dynamic styles:
import { styled } from '@mui/system';

const Button = styled('button')(({ theme, variant = 'primary' }) => ({
  backgroundColor: theme.palette[variant].main,
  color: theme.palette[variant].contrastText,
  padding: theme.spacing(1, 2),
  border: 'none',
  borderRadius: theme.shape.borderRadius,
  cursor: 'pointer',
  '&:hover': {
    backgroundColor: theme.palette[variant].dark,
  },
}));

function App() {
  return (
    <>
      <Button variant="primary">Primary</Button>
      <Button variant="secondary">Secondary</Button>
    </>
  );
}

shouldForwardProp

Control which props are forwarded to the underlying element:
import { styled } from '@mui/system';

const Box = styled('div', {
  shouldForwardProp: (prop) => prop !== 'customProp',
})(({ customProp }) => ({
  backgroundColor: customProp ? 'blue' : 'red',
}));

// customProp won't be added to the DOM
<Box customProp>Content</Box>

Default shouldForwardProp

From createStyled.js:19-21:
export function shouldForwardProp(prop) {
  return prop !== 'ownerState' && prop !== 'theme' && prop !== 'sx' && prop !== 'as';
}
By default, these props are not forwarded: ownerState, theme, sx, as.

Component Composition

Style existing styled components:
import { styled } from '@mui/system';

const BaseButton = styled('button')(({ theme }) => ({
  padding: theme.spacing(1, 2),
  border: 'none',
  borderRadius: theme.shape.borderRadius,
}));

const PrimaryButton = styled(BaseButton)(({ theme }) => ({
  backgroundColor: theme.palette.primary.main,
  color: theme.palette.primary.contrastText,
}));

Variants

Define style variants in your styled component:
import { styled } from '@mui/system';

const Button = styled('button')(({ theme }) => ({
  padding: theme.spacing(1, 2),
  borderRadius: theme.shape.borderRadius,
  border: 'none',
  variants: [
    {
      props: { variant: 'contained' },
      style: {
        backgroundColor: theme.palette.primary.main,
        color: theme.palette.primary.contrastText,
      },
    },
    {
      props: { variant: 'outlined' },
      style: {
        backgroundColor: 'transparent',
        border: `1px solid ${theme.palette.primary.main}`,
        color: theme.palette.primary.main,
      },
    },
  ],
}));

The sx Prop

By default, styled components support the sx prop:
import { styled } from '@mui/system';

const Box = styled('div')(({ theme }) => ({
  padding: theme.spacing(2),
}));

<Box sx={{ mt: 2, color: 'primary.main' }}>
  Content with sx prop
</Box>
To disable the sx prop:
const Box = styled('div', { skipSx: true })(({ theme }) => ({
  padding: theme.spacing(2),
}));

Theme Style Overrides

When you provide a name option, the component can be styled via theme:
import { styled, ThemeProvider, createTheme } from '@mui/system';

const Card = styled('div', {
  name: 'MuiCard',
  slot: 'Root',
})(({ theme }) => ({
  padding: theme.spacing(2),
}));

const theme = createTheme({
  components: {
    MuiCard: {
      styleOverrides: {
        root: {
          backgroundColor: 'lightblue',
        },
      },
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <Card>Themed card</Card>
    </ThemeProvider>
  );
}

Tagged Template Syntax

You can also use tagged template literals:
import { styled } from '@mui/system';

const Button = styled('button')`
  background-color: ${({ theme }) => theme.palette.primary.main};
  padding: ${({ theme }) => theme.spacing(1, 2)};
  border-radius: ${({ theme }) => theme.shape.borderRadius}px;
  border: none;
  color: white;
  cursor: pointer;

  &:hover {
    background-color: ${({ theme }) => theme.palette.primary.dark};
  }
`;

TypeScript

Full TypeScript support with prop types:
import { styled } from '@mui/system';

interface ButtonProps {
  variant?: 'primary' | 'secondary';
  size?: 'small' | 'medium' | 'large';
}

const Button = styled('button')<ButtonProps>(({ theme, variant = 'primary', size = 'medium' }) => ({
  backgroundColor: theme.palette[variant].main,
  padding: theme.spacing(size === 'small' ? 0.5 : size === 'large' ? 2 : 1),
}));

Best Practices

  1. Use theme values - Always reference theme for consistency
  2. Avoid inline styles - Use styled components instead
  3. Compose components - Build complex components from simpler ones
  4. Type your props - Use TypeScript for better DX
  5. Use shouldForwardProp - Prevent unwanted props in DOM

Build docs developers (and LLMs) love