# Understanding the composeClasses Utility in Material-UI: A Complete Guide

> Master Material UI's composeClasses utility. Learn how this helper function merges utility classes and user overrides to create final CSS class strings for component slots.

- Repository: [MUI/material-ui](https://github.com/mui/material-ui)
- Tags: deep-dive
- Published: 2026-02-26

---

**The `composeClasses` utility is a core helper function in Material-UI that generates final CSS class strings for component slots by merging generated utility classes with user-provided overrides.**

The `composeClasses` utility is a fundamental building block within the MUI ecosystem, located in the `@mui/base` package. It standardizes how CSS class names are constructed and applied to different parts—or "slots"—of a component. Understanding this utility reveals how Material-UI maintains consistent naming conventions while allowing flexible customization through the `classes` prop.

## What Is the composeClasses Utility?

`composeClasses` is a generic TypeScript function that transforms semantic slot definitions into ready-to-use CSS class strings. In Material-UI, a **slot** represents a distinct part of a component that can receive styling, such as the root element, an icon, or a label.

The utility takes three arguments to perform this transformation:

- **`slots`**: An object mapping each slot name to an array of class keys (e.g., `"root"`, `"disabled"`, `"sizeSmall"`). These keys represent the semantic states and variants of the component.
- **`getUtilityClass`**: A function that converts class keys into the actual utility class strings following MUI's naming convention (e.g., `getUtilityClass('root')` returns `'MuiButton-root'`).
- **`classes`** (optional): The user-provided `classes` prop that allows consumers to override or extend the generated utility classes for any slot.

## How composeClasses Works Under the Hood

The implementation in [`packages/mui-base/src/composeClasses/composeClasses.ts`](https://github.com/mui/material-ui/blob/main/packages/mui-base/src/composeClasses/composeClasses.ts) iterates over each defined slot, generates the utility classes for that slot's keys, and merges them with any user-provided overrides.

Here is the simplified core logic:

```typescript
function composeClasses<Slot extends string>(
  slots: Record<Slot, readonly string[]>,
  getUtilityClass: (slot: string) => string,
  classes: Record<string, string> = {}
) {
  const output: Partial<Record<Slot, string>> = {};

  Object.keys(slots).forEach((slot) => {
    const slotKeys = slots[slot as Slot];
    const utilityClasses = slotKeys.map(getUtilityClass);
    const userClass = classes[slot];
    output[slot as Slot] = [userClass, ...utilityClasses]
      .filter(Boolean)
      .join(' ');
  });

  return output as Record<Slot, string>;
}

```

The function places the user-provided class first in the array, followed by the generated utility classes. The `filter(Boolean)` step removes any undefined values that occur when a slot has no user override. This ensures that the final string contains only valid class names separated by spaces.

## Practical Examples of Using composeClasses

### Basic Component Implementation

Component authors use `composeClasses` within a `useUtilityClasses` hook to generate the class map for their component slots. Here is how a custom button component implements this pattern:

```tsx
// src/components/MyButton/MyButton.tsx
import { composeClasses } from '@mui/base';
import { getMyButtonUtilityClass } from './myButtonClasses';

interface MyButtonProps {
  classes?: Partial<{
    root: string;
    label: string;
    disabled: string;
  }>;
  disabled?: boolean;
  size?: 'small' | 'medium' | 'large';
}

const useUtilityClasses = (ownerState: MyButtonProps) => {
  const { disabled, size } = ownerState;

  const slots = {
    root: ['root', disabled && 'disabled', size && `size${capitalize(size)}`],
    label: ['label'],
  };

  return composeClasses(
    slots,
    getMyButtonUtilityClass,
    ownerState.classes,
  );
};

export const MyButton = (props: MyButtonProps) => {
  const { classes: userClasses = {}, ...other } = props;
  const classes = useUtilityClasses({ ...props, classes: userClasses });

  return (
    <button className={classes.root} {...other}>
      <span className={classes.label}>Click me</span>
    </button>
  );
};

```

### Overriding Classes from the Consumer Side

Consumers can override specific slots by passing a `classes` prop. The `composeClasses` utility merges these custom classes with the generated utility classes:

```tsx
<MyButton
  size="small"
  classes={{ root: 'myCustomRoot' }}
>
  Small button
</MyButton>

```

The rendered output combines the user class with the generated utility classes:

```html
<button class="myCustomRoot MuiMyButton-root MuiMyButton-sizeSmall">…</button>

```

### Integration with Styled Components

When building custom styled components that need to maintain MUI's class naming convention, `composeClasses` ensures consistency:

```tsx
import { styled } from '@mui/material/styles';
import { composeClasses } from '@mui/base';
import { getButtonUtilityClass } from '@mui/material/Button';

const ButtonRoot = styled('button')(({ theme }) => ({
  /* default style rules */
}));

export const StyledButton = (props) => {
  const { classes = {}, variant = 'contained', ...rest } = props;

  const slots = {
    root: ['root', `variant${capitalize(variant)}`],
  };

  const composed = composeClasses(slots, getButtonUtilityClass, classes);

  return <ButtonRoot className={composed.root} {...rest} />;
};

```

## Key Source Files in the Material-UI Repository

Understanding the `composeClasses` utility requires familiarity with these specific files in the `mui/material-ui` repository:

- **[`packages/mui-base/src/composeClasses/composeClasses.ts`](https://github.com/mui/material-ui/blob/main/packages/mui-base/src/composeClasses/composeClasses.ts)** – Contains the core implementation of the `composeClasses` generic function.
- **[`packages/mui-base/src/generateUtilityClass/generateUtilityClass.ts`](https://github.com/mui/material-ui/blob/main/packages/mui-base/src/generateUtilityClass/generateUtilityClass.ts)** – Provides the `generateUtilityClass` factory that creates the `getUtilityClass` functions used by `composeClasses`.
- **[`packages/mui-material/src/Button/Button.js`](https://github.com/mui/material-ui/blob/main/packages/mui-material/src/Button/Button.js)** – Demonstrates real-world usage of `composeClasses` through the `useUtilityClasses` hook pattern.
- **[`packages/mui-material/src/Button/buttonClasses.js`](https://github.com/mui/material-ui/blob/main/packages/mui-material/src/Button/buttonClasses.js)** – Defines the slot keys and utility class generator for the Button component.
- **[`packages/mui-material/src/utils/useUtilityClasses.js`](https://github.com/mui/material-ui/blob/main/packages/mui-material/src/utils/useUtilityClasses.js)** – A wrapper utility that standardizes the `composeClasses` call pattern across MUI components.

## Summary

- **`composeClasses`** is the central utility in Material-UI that transforms semantic slot definitions into final CSS class strings for component parts.
- It accepts three parameters: a **slots** object mapping slot names to class keys, a **getUtilityClass** function for generating MUI-style class names, and an optional **classes** prop for consumer overrides.
- The utility merges user-provided classes with generated utility classes, placing custom classes first to allow proper CSS specificity management.
- Located in [`packages/mui-base/src/composeClasses/composeClasses.ts`](https://github.com/mui/material-ui/blob/main/packages/mui-base/src/composeClasses/composeClasses.ts), this function ensures consistent `Mui*` naming conventions across all Material-UI components while supporting deep customization through the `classes` prop.

## Frequently Asked Questions

### How does composeClasses differ from the classes prop in Material-UI?

The `classes` prop is the public API that consumers use to inject custom class names into specific component slots. `composeClasses` is the internal utility that processes this prop. It takes the user-provided `classes` object, combines it with the automatically generated utility classes (like `MuiButton-root`), and returns the final merged class strings that get applied to the DOM elements.

### What is the relationship between composeClasses and generateUtilityClass?

`generateUtilityClass` is a factory function that creates the `getUtilityClass` function required by `composeClasses`. While `generateUtilityClass` produces the naming convention logic (transforming a slot key like `"root"` into `"MuiComponent-root"`), `composeClasses` orchestrates the application of these names across multiple slots and handles the merging with user overrides. You can find `generateUtilityClass` in [`packages/mui-base/src/generateUtilityClass/generateUtilityClass.ts`](https://github.com/mui/material-ui/blob/main/packages/mui-base/src/generateUtilityClass/generateUtilityClass.ts).

### Does using composeClasses impact runtime performance?

The performance impact is minimal. `composeClasses` performs simple array mapping and string joining operations that execute quickly during component render cycles. Material-UI typically calls this utility within a `useUtilityClasses` hook, ensuring that class generation logic is centralized and memoized where appropriate. The deterministic nature of the class generation also helps with CSS caching and server-side rendering consistency.

### When should custom component authors use composeClasses?

Component authors should use `composeClasses` whenever building reusable components that follow Material-UI's styling architecture and need to support the `classes` prop for customization. It is essential when you want to maintain the `MuiComponent-slot` naming convention, support style overrides through the theme, and allow consumers to inject custom class names into specific slots. This utility ensures your custom components behave consistently with official MUI components regarding class name generation and customization patterns.