Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add my custom component to Mui Theme options so that I can override it?

I've been messing with this for a bit and I keep running into type errors, so there must be something that I'm missing.

What I want to do is create my own component and then be able to override some styles within the components section of a Theme. From what I've read, I need to add the component to the Components interface, which allows me to add that Custom component to the components section in ThemeOptions, but I can't find anything that describes how to add either styleOverrides or custom props like root or bottom so that I can pull those out and apply the styles to the component.

// module aug
declare module '@mui/material/styles'{
   interface Components {MyComponent?:type of MyComponent}
}
// my component
type MyComponentProps = {prop1:string, prop2:string, styleOverrides?:{bottom:CSSProperties}
const MyComponent = ({prop1:string, props2:string}:MyComponentprops) => { return <> ... </> }
// theme options
const options = {components:MyComponent:{styleOverrides:{bottom:{color:'red'}}}}


I get an error that the type {styleOverrides?:bottom:{color:string} } is not comparable to {prop1:string, prop2:string, styleOverrides}:MyComponentProps. type {styleOverrides?:bottom:{color:string}} provides no match for the signature {prop1:string, prop2:string, styleOverrides}:MyComponentProps):Element

I've tried several different ways of formatting the props for the component, but the styleOverrides always comes back empty.

What am I doing wrong here?

like image 720
gin93r Avatar asked Oct 31 '25 00:10

gin93r


1 Answers

In your module augmentation example you have interface Components {MyComponent?:type of MyComponent}, but you need to define the full structure of the type that would occur within MyComponent in the theme. This means you need to specify the full structure of the defaultProps key and the styleOverrides key (also variants if you want to support that concept, but I don't bother with variants in my example). You can see here how MUI defines this for each of its components.

The defaultProps key can have the same type as the props for your component (MyComponentProps in my example).

The styleOverrides key is quite a bit more complicated. You can see here how MUI defines this for components and my example re-uses MUI's OverridesStyleRules type. The main "input" into the generics for that type is the allowed class keys. My example defines that in the type MyComponentClassKey. To model off of the MUI approach, typically you would define a "root" class key for the outermost component, and then additional keys for any elements nested within that (e.g. "bottom" in my example).

The next step is to leverage the defaultProps and styleOverrides from the theme in your component. You can see here how MUI uses useThemeProps to support default props and my example uses the same approach. To support the style overrides, you use the styled API passing the second options argument indicating the component name, the slot (i.e. which CSS class key), and the overridesResolver which determines which portions of the style overrides are applicable for the slot (and it can potentially take props/state into account if dealing with variants). You can see examples of this within MUI here.

Below is a full working example:

import * as React from "react";
import {
  createTheme,
  ThemeProvider,
  Theme,
  styled,
  useThemeProps
} from "@mui/material/styles";
import { OverridesStyleRules } from "@mui/material/styles/overrides";

interface MyComponentProps {
  greetee?: string;
}
type MyComponentClassKey = "root" | "bottom";

const MyComponentRoot = styled("div", {
  name: "MyComponent",
  slot: "Root",
  overridesResolver: (props, styles) => styles.root
})(({ theme }) => {
  return {
    padding: 8
  };
});

const MyComponentBottom = styled("div", {
  name: "MyComponent",
  slot: "Bottom",
  overridesResolver: (props, styles) => styles.bottom
})(({ theme }) => {
  return {
    borderBottom: "1px solid black"
  };
});

const MyComponent = React.forwardRef(function MyComponent(
  inProps: MyComponentProps,
  ref
) {
  const props = useThemeProps({ props: inProps, name: "MyComponent" });
  const { greetee } = props;
  return (
    <MyComponentRoot>
      Hello {greetee}
      <MyComponentBottom />
    </MyComponentRoot>
  );
});

declare module "@mui/material/styles" {
  interface Components {
    MyComponent?: {
      defaultProps?: MyComponentProps;
      styleOverrides?: Partial<
        OverridesStyleRules<MyComponentClassKey, "MyComponent", Theme>
      >;
    };
  }
}

const theme = createTheme({
  components: {
    MyComponent: {
      defaultProps: {
        greetee: "World!"
      },
      styleOverrides: {
        root: {
          backgroundColor: "green",
          padding: 16
        },
        bottom: {
          borderColor: "purple"
        }
      }
    }
  }
});

export default function CustomStyles() {
  return (
    <ThemeProvider theme={theme}>
      <MyComponent />
    </ThemeProvider>
  );
}

Edit custom component with styleOverrides support

like image 71
Ryan Cogswell Avatar answered Nov 01 '25 13:11

Ryan Cogswell