Extend MUI components from theme provider - reactjs

Currently I'm wondering about if there is the possibility of extending components, by adding new props directly from the theme provider.
For example, let's take the IconButton component, I want to add square prop to this component
import { Components, Theme } from '#mui/material';
export const MuiIconButton: Components<Theme>['MuiIconButton'] = {
defaultProps: {
square: true
},
styleOverrides: {
root: ({ ownerState }) => ({
//here I would like to access the square prop
borderRadius: ownerState.square ? 0 : 50,
})
}
};
declare module '#mui/material/IconButton' {
interface IconButtonPropsOverrides {
square: boolean;
}
}
By taking a look into IconButton.d.ts from MUI,
export interface IconButtonPropsColorOverrides {}
export interface IconButtonPropsSizeOverrides {}
There is no override for props available...
My question is if there is any possibility of adding this override without having to alter the MUI code base. Is there a general approach over this?
Thanks

Related

Applying Material UI styleOverrides at the component-level with styled()

I'm not sure if this is possible or not, after looking at Material UI's documentation on How to Customize, but I'm trying to isolate styleOverrides for a given component using styled() rather than applying a lot of overrides within a global theme file.
Currently, my theme file looks something like this, with some typography and palette overriding Material UI's default theme:
const theme = createTheme({
palette: { ...
},
typography: { ...
}
});
When I use a Chip component (rendered in Storybook currently) and pass in success, primary, secondary, etc. into the color prop, the corresponding theme colors are applied. However, when I try to override the theme files, using styled(), the colors defined in the theme are still being applied - as opposed to my overrides defined. My component file looks like the following:
import { styled } from '#mui/material/styles';
import MuiChip, { ChipProps } from '#mui/material/Chip';
const Chip = styled(MuiChip)<ChipProps>(({ theme }) => ({
colorPrimary: {
backgroundColor: theme.palette.primary.light
},
colorSecondary: {
backgroundColor: theme.palette.secondary.light
}
}));
export default Chip;
You can create your own custom variant and define your own styles to it
const theme = createTheme ({
components : {
MuiButton : {
variants : [
{ props : { variant : 'YouVarName'},
style: { //..your styles } ,
},},

not able to pass theme to "#mui/system" styled()

I am attempting to pass a theme by doing:
declare module "#mui/styles/defaultTheme" {
// eslint-disable-next-line #typescript-eslint/no-empty-interface
interface DefaultTheme extends Theme {}
}
ReactDOM.render(
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<Main />
</ThemeProvider>
</StyledEngineProvider>,
document.getElementById("root")
);
which I them attempt to read by doing:
import { styled } from "#mui/system";
type StyledTabProps = {
isActive: boolean;
};
const StyledTab = styled("div", {
shouldForwardProp: (prop) => prop !== "isActive"
})<StyledTabProps>(({ theme, isActive }) => {
console.log("theme", theme);
return {
color: isActive ? "red" : "blue"
};
});
the theme which I attempt to pass is different from the one that ends up getting console.logged (is missing properties in palette object)
code sandbox of the issue can be found here:
https://codesandbox.io/s/wandering-https-ubhqs?file=/src/Main.tsx
You just need to use ThemeProvider from #mui/material/styles, not from #mui/styles. Then it would work.
Please refer to this
// index.tsx
...
import { Theme, ThemeProvider, StyledEngineProvider } from "#mui/material/styles";
...
And also MUI v5 theme structure is a bit different not exactly the same to the v4.
You could not use adaptV4Theme, just update the theme structure, but please define some custom types for it.
(The codesandbox says adaptV4Theme is deprecated somehow.)
For example, you used overrides option for the theme object, but it is removed so you need to use components instead of it. https://mui.com/guides/migration-v4/#theme-structure
...
// styles/theme.ts
export default createTheme(
{
...
components: {
MuiInputBase: {
root: {
...
}
...

Override Box component in createTheme

I have an application that utilizes box's in place of where divs would typically be placed to stay within the MUI ecosystem. My question is, is it possible to have a global theme override for all box components much like how you can globally override the background color for all cards using theme provider.
You can override the Card styles globally using createTheme() because the Card has a name and a styleOverrides callback when it is styled using the styled() API. However, the Box does not, as you can see from the definition here.
const theme = createTheme({
components: {
// this works
MuiCard: {
styleOverrides: {
//
}
},
// this does not work
MuiBox: {
styleOverrides: {
//
}
}
}
});
If you want to create a base component like the Box that can be styled globally by createTheme, you need to define the following properties in the options when calling styled()
name: so the styled engine can identify your component.
overridesResolver: to let MUI know how to resolve the final styles (by combining with other styles created by custom variant, prop and state of the component).
Below is the minimal example for demonstration:
const theme = createTheme({
components: {
MuiDiv: {
styleOverrides: {
root: {
backgroundColor: "green"
}
}
}
}
});
const Div = styled("div", {
name: "MuiDiv",
overridesResolver: (props, styles) => {
return [styles.root];
}
})();
<Div sx={{ width: 10, height: 10 }} />
Live Demo
References
https://mui.com/system/styled/#api
https://mui.com/system/styled/#custom-components

How can I add a global control matcher in Storybook?

I am building a component library in React and TypeScript using Storybook. Many components have an icon prop. In the code snippet below, you can see a Component story example where I customize the icon prop's control using a select type with icon options.
// Component.stories.js
import { Component } from './component';
import { iconOptions, DefaultIcon } from "./icons";
export default {
component: Component,
title: 'Component',
argTypes: {
icon: {
control: {
type: 'select'
},
options: iconOptions,
defaultValue: DefaultIcon
}
}
};
The problem is that this setup is repetitive for all components using icon prop. Instead, I would like to configure this globally for all components. So any prop called icon would automatically get a select control with icon options.
I tried editing the .storybook/preview.js file:
export const parameters = {
controls: {
icon: {
control: {
type: 'select'
},
options: iconOptions,
defaultValue: DefaultIcon,
}
}
};
However, that did not work.
How can I configure such a global control?

Overwrite Material UI prop types

I'm using React, Typescript, and Material UI. I'm using createMuiTheme.props to disable ripple for the ListItem component globally like this:
createMuiTheme({
props: {
MuiListItem: {
disableRipple: true,
disableTouchRipple: true,
disableFocusRibble: true
}
}
})
But Typescript complains that:
Types of property 'MuiListItem' are incompatible.
Type '{ disableRipple: boolean; disableTouchRipple: boolean; disableFocusRibble: boolean; }' has no properties in common with type 'Partial<OverrideProps<ListItemTypeMap<{}, "li">, "li">>'.ts(2322)
So I created a types.d.ts file in the project root and added the following code:
import { ListItemProps as PrevListItemProps } from "#material-ui/core/ListItem";
import { ButtonBaseProps } from "#material-ui/core/ButtonBase";
declare module "#material-ui/core/ListItem" {
export type ListItemProps = PrevListItemProps & ButtonBaseProps;
}
Which fixes the previous issue but now Typescripts errors because:
ListItem.d.ts(50, 13): 'ListItemProps' was also declared here.
Any idea how to fix this? Or disable ripple for ListItem without passing it each time to components?
Thanks!
You can disable ripple effect globally for all buttons:
https://material-ui.com/ru/getting-started/faq/
import { createMuiTheme } from '#material-ui/core'
const theme = createMuiTheme({
props: {
MuiButtonBase: {
disableRipple: true,
},
},
})
Or you can create your own component:
import ListItem from '#material-ui/core/ListItem'
const CustomListItem = props => <ListItem {...props} button disableRipple disableTouchRipple />

Resources