Ant design Menu.Item custom style in react - reactjs

Hi everyone i learning ant design with React + typescript. i need to override some default styles in Menu.Item components. but i have a problem with remove border-right style when user click that Menu.Item using styleComponent. i don't know the exact way but i inspect that component and i picked the className from inspection and made border-right: 3px solid transparent
but still it didn't work for me Here is the code i attach below
import { Layout, Menu } from "antd";
import React from "react";
import styled from "styled-components";
import { Flex } from "../styleComponents/commonUtilsStyles";
import {
MenuUnfoldOutlined,
MenuFoldOutlined,
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
} from "#ant-design/icons";
import SubMenu from "antd/lib/menu/SubMenu";
const MenuItem = styled(Menu.Item)`
.ant-menu-vertical .ant-menu-item::after,
.ant-menu-vertical-left .ant-menu-item::after,
.ant-menu-vertical-right .ant-menu-item::after,
.ant-menu-inline .ant-menu-item::after {
border-right: 3px solid transparent !important;
}
`;
const { Header, Sider, Content } = Layout;
const FlexContainer = styled(Flex)`
background-color: white;
box-shadow: 6px 6px 32px #cccccc, -6px -6px 32px #f4f4f4;
`;
const HeaderContainer: React.FC = () => {
return (
<>
<Layout>
<Sider>
<Menu mode="inline">
<SubMenu key="submenu" title="number">
<MenuItem className="no-border" key="1">
one
</MenuItem>
<MenuItem className="no-border" key="2">
two
</MenuItem>
<MenuItem className="no-border" key="3">
three
</MenuItem>
</SubMenu>
<MenuItem className="no-border" key="11">
one 1
</MenuItem>
<MenuItem className="no-border" key="21">
two 1
</MenuItem>
<MenuItem className="no-border" key="31">
three 1
</MenuItem>
</Menu>
</Sider>
</Layout>
<h1>hello</h1>
</>
);
};
export default HeaderContainer;
output
but i need to remove that border line style when user click that menu it

Create a css file and set the border-right property to 0px for following classes to remove the right border.
index.css
.ant-menu-vertical .ant-menu-item::after,
.ant-menu-vertical-left .ant-menu-item::after,
.ant-menu-vertical-right .ant-menu-item::after,
.ant-menu-inline .ant-menu-item::after {
border-right: 0px;
}
Screenshot:

I found the best way is using Emotion React
import styled from "#emotion/styled";
import { Menu } from "antd";
and then overwrite the style (you need to inspect to know the antd css class)
/**
* ant-menu-item:hover::after
* ant-menu-item-selected
* ant-menu-item-selected:after
*/
const CustomMenu = styled(AntMenu)`
&& .ant-menu-item:hover::after {
border-bottom: 0px solid transparent;
}
&& .ant-menu-item-selected {
background-color: #EEF6F7;
border-top: 4px solid #B80012;
border-radius: 0px;
color: #B80012;
}
&& .ant-menu-item-selected:after {
border-bottom-width: 0px;
border-bottom-color: transparent;
}
`;
Finally, use it as a component
return (
<ConfigProvider theme={theme}>
<CustomMenu
onClick={onClick}
selectedKeys={[current]}
mode="horizontal"
items={menuItems}
{...props}
/>
</ConfigProvider>
);
This is how I test in Storybook
Custom AntDesign Horizontal menu
EXPLAINATION
Why can we do this?
Firstly, Emotion styled component' styled can style any component as long as it accepts a className prop. https://emotion.sh/docs/styled
Secondly, let's check Ant Design source code, go to Menu component, we will see index.tsx import InternalMenu in this line import InternalMenu from './menu';
Then, we go to menu.tsx, which export InternalMenu component and see its props here const InternalMenu = forwardRef<RcMenuRef, InternalMenuProps>((props, ref) => {...}
And scroll down, in the destructuring part it has const { prefixCls: customizePrefixCls, className,...restProps} = props;
=> Here you can see it accepts className props, which means you can apply what styled component approach which EmotionJS offers.
Have fun!
Binh Truong :)

Related

Material-ui don't change the style when the MenuItem has selected

Currently, I styled background-color: red; if the MenuItem that has selected={true}
and if I hover the option, MenuItem background-color will change to green.
But when I hover over the MenuItem that has selected={true}, the background-color will be light-blue which is mui default.
I'd like to keep background-color: red; for MenuItem that has selected={true} even if this component get hovered over.
index.js
import * as React from "react";
import Paper from "#mui/material/Paper";
import MenuList from "#mui/material/MenuList";
import Stack from "#mui/material/Stack";
import { MenuItem } from "./styles";
export default function MenuListComposition() {
return (
<Stack direction="row" spacing={2}>
<Paper>
<MenuList>
<MenuItem selected={true}>Profile</MenuItem>
<MenuItem>My account</MenuItem>
<MenuItem>Logout</MenuItem>
</MenuList>
</Paper>
</Stack>
);
}
styles.js
import styled from "styled-components";
import { default as MuiMenuItem } from "#mui/material/MenuItem";
export const MenuItem = styled(MuiMenuItem)`
color: blue;
padding: 20px;
&.Mui-selected {
background-color: red;
}
&:hover {
background-color: green;
}
`;
You are almost there, just need to add the &.Mui-selected:hover to overwrite the default background color.
export const MenuItem = styled(MuiMenuItem)`
color: blue;
padding: 20px;
&.Mui-selected {
background-color: red;
}
// Add this
&.Mui-selected:hover{
background-color: red;
}
&:hover {
background-color: green;
}
`;
Here is the working codesandbox

How to change a component's color with styled-components?

I want to change a component Area's background color when move link hover on it.
import Link from "next/link";
...
export const ShowField: React.FC<ShowFieldProps> = ({ link, name }) => {
return (
<Link href={link}>
<YellowLink>
<Area backgroundColor="blue">
<Area>
<Name text={name} />
</Area>
</Area>
</YellowLink>
</Link>
);
};
const YellowLink = styled.div`
&:hover ${Area} {
background-color: yellow;
}
`;
Area is a self-created component. There is some errors if use it in the styled.div:
No overload matches this call.
Overload 1 of 3, '(first: TemplateStringsArray | CSSObject |
If use this way
const YellowLink = styled.div`
a {
&:hover {
background-color: yellow;
}
}
`
There happens nothing on the page. How to haddle <Area backgroundColor="blue"> and change color for it?
Without seeing more of the code for the other components, this may not work for you. One approach you could take is styling a Link for your YellowLink component where you define the styles of that link.
For example:
// Create a styled link component...
const StyledLink = styled(Link)`
background-color: ${(props) => props.backgroundColor};
// Add any additional styles you need for the link
&:hover {
background-color: yellow;
}
`;
// Usage
return (
<StyledLink href={link} backgroundColor="blue">
<Name text={name} />
</StyledLink>
);

Using Material-UI System with Default Components

Is it possible to use Material-UI System with the default Material UI components? For example, this currently does not work:
<AppBar bgColor="secondary.main" p={{ xs: 2, sm: 3, md: 4 }}>...</AppBar>
I am wondering, though, is there a way to get this to work (not just for AppBar, but for any Material UI component)? I.e., is there a way to integrate System with the default Material UI components?
If so, how?
Thanks.
The Box component can be used to add the Material-UI System features to other components by using its component prop. One caveat is that if you try to change styling that is explicitly controlled by the component, you may run into specificity issues. For instance the styling of the background color on the Button in my example below doesn't work correctly if you flip the order of the Button and Box imports since this causes the order of their styles in the <head> to also be flipped.
import React from "react";
import styled, { ThemeProvider as SCThemeProvider } from "styled-components";
import { useTheme, StylesProvider } from "#material-ui/core/styles";
import MuiAppBar from "#material-ui/core/AppBar";
import Button from "#material-ui/core/Button";
import Box from "#material-ui/core/Box";
const AppBar = styled(MuiAppBar)`
background-color: red;
${props => props.theme.breakpoints.up("sm")} {
background-color: orange;
}
${props => props.theme.breakpoints.up("md")} {
background-color: yellow;
color: black;
}
${props => props.theme.breakpoints.up("lg")} {
background-color: green;
color: white;
}
`;
export default function App() {
const muiTheme = useTheme();
return (
<StylesProvider injectFirst>
<SCThemeProvider theme={muiTheme}>
<Box component={AppBar} p={{ xs: 2, sm: 3, md: 4, lg: 5 }}>
Sample AppBar 1
</Box>
<div style={{ height: "100px" }} />
<Box component={Button} bgcolor="secondary.main">
Sample Button
</Box>
</SCThemeProvider>
</StylesProvider>
);
}
Related answer: Material-UI Grid does not hide whe use Display

Extend a Styled Component from a different file

What I'm trying to achieve is to be able to add extra styling to my Button.tsx(essentially extending the styles) when using this component in different files. As you can see in my Button.tsx I have defined some default styles I would like the button to have, but as I use more buttons across my app, I might want to change the background or color, etc.
One thing I could do is this:
Example of not what I want to do:
import React from 'react'
import styled from 'styled-components'
interface IButton = {
children: string
}
export default function Button({ children }: IButton) {
const Button = styled.button`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
const RedButton = styled(Button)`
// Inherits all of the styles from Button.
background: red;
`
return (
<Button>{children}</Button
)
}
This example will inherit my Button styles and then allows me to extend. The problem with this solution is, if I decide to add more buttons, I will always have to come back to this file and then add the different variants, which could start to make this file get pretty chunky and messy.
Ideally I would like to extend my <Button> from the App.tsx file, or which ever file I'm using my <Button> in.
How could I adjust the code below to achieve this?
Button.tsx
import React from 'react'
import styled from 'styled-components'
interface IButton = {
children: string
}
export default function Button({ children }: IButton) {
const Button = styled.button`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
return (
<Button>{children}</Button
)
}
App.tsx
import React from 'react'
import styled from 'styled-components'
export default function App() {
return (
{/* This button would render with the default styles from Button.tsx */}
<Button>Button One</Button>
{/* This button would render with extended styles, a blue background for example */}
<Button>Button Two</Button>
)
}
In your App.tsx you can do the same:
const BlueButton = styled(Button)`
background: blue;
`
what styled-components does is it creates a class with background blue and pass it to your Button. so in your Button.tsx you need to accept the css class
export default function Button({ className, children }: IButton) {
const Button = styled.button`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
return (
<Button className={className}>{children}</Button
)
}
Edit
another way to do is to export the style like this
const BaseStyles = css`
padding: 1em;
background: #ccc;
border-radius: 5px;
`
const BaseButton = styled.button`
${BaseStyles}
`
Then later override the styles
const BlueButton = styled.button`
${BaseStyles}
background: blue;
`

How do I over write nested classes of material-ui in styled-components?

Method 1:
const StyledTextField = styled(({ ...rest }) => (
<OutlinedInput {...rest} classes={{ root: 'outlinedRoot' }} />
))`
.outlinedRoot {
.$notchedOutline {
border-color: red;
}
}
background: #fff;
border-radius: 4px;
color: #808080;
height: 53px;
`;
Method 2:
const StyledTextField = styled(OutlinedInput).attrs({
classes: { root: 'outlinedRoot', notchedOutline: 'notchedOutline' }
})`
.outlinedRoot {
.notchedOutline {
border-color: red;
}
}
background: #fff;
border-radius: 4px;
color: #808080;
height: 53px;
`;
I have seen also what classes needs to be added and read articles about that, but I am not able to overwrite
I tried above two ways to change the outline color but i am not able to do that
Below is an example of one way to do this. To do this with TextField rather than OutlinedInput, just add a space before .MuiOutlinedInput-root so that you match that as a descendant of TextField rather than matching that as one of the other classes on the root element. .MuiOutlinedInput-root is actually unnecessary for the styling except for helping with CSS specificity.
import React from "react";
import ReactDOM from "react-dom";
import OutlinedInput from "#material-ui/core/OutlinedInput";
import styled from "styled-components";
const StyledOutlinedInput = styled(OutlinedInput)`
&.MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline {
border-color: green;
}
&:hover.MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline {
border-color: red;
}
&.MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline {
border-color: purple;
}
`;
function App() {
return (
<div className="App">
<StyledOutlinedInput defaultValue="My Default Value" />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Related answers:
Change border color on Material-UI TextField
Change outline for OutlinedInput with React material-ui
How do I override hover notchedOutline for OutlinedInput
Global outlined override

Resources