How do customise a component's CSS selectors in FluentUI - reactjs

I am trying to customise the behavior of an FluentUI component when it is hovered over (A Primary Button in this case). How do I customise CSS selectors when I am using Microsoft's React FluentUI library.
I tried this initially (This approach is deprecated now, in favor of the method where you add selectors as siblings)...
export const MyButton = (props: IButtonProps) => {
const styles: IButtonStyles = {
root: {
backgroundColor: '#000000',
selectors : {
':hover': {
backgroundColor: '#0000ff'
}
}
},
}
return (
<PrimaryButton styles={styles} {...props} />
);
}
Then I tried this:
export const MyButton = (props: IButtonProps) => {
const styles: IButtonStyles = {
root: {
backgroundColor: '#000000',
':hover': {
backgroundColor: '#0000ff'
}
},
}
return (
<PrimaryButton styles={styles} {...props} />
);
}
Both approaches do not seem to be working. Am I missing something?

With new FluentUI you can modify styles trough specific props based on button state:
export const MyButton = (props: IButtonProps) => {
const styles: IButtonStyles = {
root: {
backgroundColor: '#000000',
},
rootHovered: {
backgroundColor: '#0000ff',
},
}
return (
<PrimaryButton styles={styles} {...props} />
);
}
Codepen working example.
On this link you have IButtonStyles interface.

Related

Chakra UI __css on sub-component isn't being applied when styling multipart components

I am using Typescript, React(create-react-app) and Chakra.
As in the title, css on <DropdownItem> component isn't being applied.
Css on <Dropdown> works normally.
I have this code basically copied from the styling multipart components and when comparing it to the List component from the Chakra source code, it looks okay to me. But it doesn't work for some reason.
There is no errors and when console logging the CSSDict from useStyles() and useMultiStyleConfig() it logs the styles normally. I think it must be breaking at __css={styles.item}.
Thank you in advance.
Select.tsx
<Dropdown onClick={() => setOpen(!open)}>
<DropdownItem>{currItem}</DropdownItem>
</Dropdown>
Dropdown.tsx
const [StylesProvider, useStyles] = createStylesContext("Dropdown");
export function Dropdown(props: any): any {
const { size, variant, children, ...rest } = props;
const styles = useMultiStyleConfig("Dropdown", { size, variant });
return (
<List __css={styles.dropdown} {...rest}>
<StylesProvider value={styles}>{children}</StylesProvider>
</List>
);
}
export function DropdownItem(props: any): any {
const styles = useStyles();
return <ListItem __css={styles.item} {...props} />;
}
theme.ts
export const theme = extendTheme({
components: {
Button,
Dropdown,
},
colors: {
main: {
independence: "#3D405B",
purplenavy: "#51557A",
darkbluegray: "#656A99",
terracotta: "#E07A5F",
eggshell: "#F4F1DE",
},
},
styles: {
global: () => ({
body: {
bg: "main.independence",
height: "100%",
},
}),
},
shadows: {
terra: "2px -2px #E07A5F",
eggshell: "2px -2px #F4F1DE",
},
});
database.style.ts
export const Dropdown: ComponentStyleConfig = {
parts: ["dropdown", "item"],
// The base styles for each part
baseStyle: {
dropdown: {
position: "relative",
display: "inline-block",
width: "100px",
cursor: "pointer",
fontSize: "calc(35px, 0.87vw)",
h: "100%",
zIndex: "10",
},
item: {
h: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
_hover: { bg: "main.violetLt", borderRadius: "15px 0 0 15px" },
fontWeight: "600",
bg: "orange",
},
},
// The size styles for each part
sizes: {},
// The variant styles for each part
variants: {},
// The default `size` or `variant` values
defaultProps: {},
};
Edit 1
Looking at it from React Devtools, <ListElement> is the last component that gets the correct __css prop, which then disappears in <li> child.
Edit 2
export function DropdownItem(props: any): any {
const styles = useStyles();
return <chakra.li __css={styles.item} {...props} />;
}
Using <chakra.li> instead of <ListElement> somehow solves the problem and the css is being passed and applied but I still don't understand why.

MUI v5 passing props to CSS theme using styled()

Previously, in Material-UI v4, I had this bit of code
const { customPadding } = props;
const classes = useStyles({
padding: customPadding,
} as any);
To pass props to the classes of an element.
But v5 uses emotion instead of JSS, where I do something like this instead.
const StyledContainer = styled(Container)(({theme}: any) => ({
[`&.${classes.FullPageLayoutRoot}`]: (props: any) => ({
minHeight: `calc(100vh - ${appBarHeight}px - ${theme.spacing(1)} - 1px)`,
display: 'flex',
}),
[`&.${classes.middle}`]: {
alignItems: 'center',
},
[`& .${classes.paper}`]: (props: any) => ({
backgroundColor: grey[800],
marginBottom: theme.spacing(1),
padding: theme.spacing(props.padding),
minWidth: '100%',
})
}));
...
return(
<StyledContainer maxWidth={maxWidth} fixed className={clsx(classes.FullPageLayoutRoot, {
[classes.middle]: middle,
})}>
<Paper className={clsx(classes.paper, classes.padding, className)} {...PaperProps} >
{content}
</Paper>
</StyledContainer>
)
How would I accomplish this in Material-UI v5?
They're passed along with the theme property in the callback:
const MyDiv = styled("div", {
// indicate that this prop name should be used to conditionally
// style the component only and should not be spread to the DOM element.
shouldForwardProp: (propName) => propName !== "isRed"
})(({ theme, isRed }) => ({
backgroundColor: isRed ? "red" : theme.palette.primary.main
}));
export default function ThemeUsage() {
return (
<MyDiv isRed>Styled div with theme</MyDiv>
);
}
Live Demo

TypeError: theme is undefined - When trying to render Material UI component

I am having trouble rendering my react component since I separated my jss file and changed it from makeStyles to withStyles to avoid a hook problem.
I am getting an error message in my jss styling file as a couple of the methods have a 'theme' in the parenthesis for the styling to work off.
How do I go about changing this so that it renders correctly?
accessControl.component.js
import {connect, useSelector} from "react-redux";
import DataTable from "./userListTable.component";
import {Paper} from "#material-ui/core";
function AdminAccessControl(props) {
const { children, value, index, ...other } = props;
// select user object from redux
const user = useSelector(state => state.user);
// select school object from redux
const school = useSelector(state => state.diveSchool);
const classes = useStyles();
const [role, setRole] = useState({
userRole: "",
});
const handleChange = (property) => (e) => {
setRole({
// override the changed property and keep the rest
...role,
[property]: e.target.value,
});
}
return (
<div className={classes.root}>
<StyledTabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
aria-label="styled tabs example"
centered>
<StyledTab label="User Access Control" />
{/*<DataTable />*/}
<StyledTab label="Scuba School Access Control" />
{/*<DataTable />*/}
</StyledTabs>
<Typography className={classes.padding} />
</div>
);
}
function mapStateToProps(state){
const { user } = state.auth;
const { school } = state.diveSchool;
return {
user,
school,
};
}
export default compose(
connect(
mapStateToProps,
),
withStyles(useStyles)
)(AdminAccessControl);
myJss-style.js
export const useStyles = (theme) => ({
root: {
flexGrow: 1,
},
padding: {
padding: theme.spacing(3),
},
demo1: {
backgroundColor: theme.palette.background.paper,
},
demo2: {
backgroundColor: '#2e1534',
},
});
export const StyledTabs = () => ({
indicator: {
display: 'flex',
justifyContent: 'center',
backgroundColor: 'transparent',
'& > span': {
maxWidth: 40,
width: '100%',
backgroundColor: '#635ee7',
},
},
})((props) => <StyledTabs {...props} TabIndicatorProps={{ children: <span /> }} />);
export const StyledTab = (theme) => ({
root: {
textTransform: 'none',
color: '#fff',
fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.pxToRem(15),
marginRight: theme.spacing(1),
'&:focus': {
opacity: 1,
},
},
})((props) => <StyledTab disableRipple {...props} />);

How to change the progress bar background color dynamically in react material ui?

//Component Style:
const BorderLinearProgress = withStyles(theme => ({
bar: {
borderRadius: 8,
backgroundColor: "red"
}
}))(LinearProgress);
//Component use:
<BorderLinearProgress variant="determinate" value={50} />
I am new to react and material-ui.
In the above code I need to pass or change bar:backgroundColor dynamically.
Please let me know what are the options to do.
Thanks in advance
You can pass your color with the theme variable.
// Passing theme
const useStyles = makeStyles((theme) => ({
bar: props => ({
borderRadius: 8,
backgroundColor: props.color
})
}))
//Using style in component
...
const [progressColor, setProgressColor] = React.useState({ color: 'red' })
const classes = useStyles(progressColor);
// Update color based on your requirements i.e. setProgressColor({color: 'green'}) in some useEffect() when progress crosses some threshold
return (
<LinearProgress color={classes.bar} />
)
...
You can find an example in official docs: https://material-ui.com/styles/basics/#adapting-based-on-props
Below code works fine with dynamic values and colors
const LinearProgressBar: React.FC<ILinearProps> = ({ value, color }) => {
const useStyles = makeStyles({
root: {
height: 10,
borderRadius: 5
},
colorPrimary: {
backgroundColor: '#E9E9E9'
},
bar: {
borderRadius: 5,
backgroundColor: color
}
});
const classes = useStyles();
return (
<LinearProgress
variant="determinate"
value={value}
classes={{
root: classes.root,
colorPrimary: classes.colorPrimary,
bar: classes.bar
}}
/>
);
};
export default LinearProgressBar;
You can do it in two ways:
1). just Write
<LinearProgress style={{backgroundColor: "red"}} variant="determinate" value={50} />
2).
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const styles = {
LinerProgressColor: {
backgroundColor: 'red',
},
};
function BorderLinearProgress (props) {
return <LinearProgress className={LinerProgressColor} variant="determinate" value={50} />;
}
export default withStyles(styles)(BorderLinearProgress);

How to pass className style to sub component in `material-ui`?

Material UI uses className for stying. But how can I pass the style to sub react component?
Below is my style definition.
const styles = createStyles({
root: {
backgroundColor: 'transparent !important',
boxShadow: 'none',
paddingTop: '25px',
color: '#FFFFFF'
},
subComponentStyle: {
...
}
});
And I use this like:
...
const NavigationBar = (props) => {
const { classes } = props;
return (
<div className={classes.root}>
// Add other code here
<SubComponent ... > // how to pass `classes.subComponentStyle` style here
</div>
)
}
...
export default withStyles(styles)(NavigationBar);
If the SubComponent component is also exported with withStyles. How can I pass some styles to override its own styling?
My SubComponent is exported as:
const styles = createStyles({
...
});
const SubComponent = ({classes}) => {
...
}
export default withStyles(styles)(SubComponent);
as you can see, it has its own classes. I don't want to override its classes completely. Is there a way to merge the passed in classes with its internal classes?
// Edited to merged styles
MUI will merge styles if you pass the classes as well as wrap the child withStyles. ie:
import { styles } from './NavStyles'
const NavigationBar = (props) => {
const { classes } = props;
return (
<div className={classes.root}>
<SubComponent classes={classes} >
</div>
)
};
export default withStyles(styles)(NavigationBar);
and in then also apply styles to the child component
import { styles } from './SubCompStyles'
const SubComponent = ({classes}) => {
// classes object is a merge of both parent and child styles
// ... component logic
};
export default withStyles(styles)(SubComponent)
Heres how you can do it with hook API:
Sub component
const useStyles = makeStyles((theme) => ({
root: {
borderRadius: 3,
color: 'white',
padding: '0 30px',
width: '12em',
height: 43,
borderRadius: 21.5,
textTransform: 'capitalize',
... your styles here.
},
}))
export default function AuthSecondaryButton(props) {
const classes = useStyles()
console.log('s', props.className)
return (
<Button
{...props}
className={clsx({
[classes.root]: true,
[props.className]: true,
})}
/>
)
}
Parent component
const useStyles = makeStyles((theme) => ({
secondaryButton: {
marginTop: theme.spacing(1),
},
}))
export default function App(props) {
const classes = useStyles()
return(
<AuthSecondaryButton
onClick={onClickSecondaryButton}
className={classes.secondaryButton}
>
Sign Up
</AuthSecondaryButton>
)
A slight tweak to #clever_usernames approach.
This uses classnames package instead of the clsx package, which we use in our project.
Replacing this...
className={clsx({
[classes.root]: true,
[props.className]: true,
})}
with this...
className={classNames(classes.root, props.className)}
Full Example
Sub component
import classNames from 'classnames'
const useStyles = makeStyles((theme) => ({
root: {
borderRadius: 3,
color: 'white',
padding: '0 30px',
width: '12em',
height: 43,
borderRadius: 21.5,
textTransform: 'capitalize',
... your styles here.
},
}))
export default function AuthSecondaryButton(props) {
const classes = useStyles()
console.log('s', props.className)
return (
<Button
{...props}
className={classNames(classes.root, props.className)}
/>
)
}
Parent component
const useStyles = makeStyles((theme) => ({
secondaryButton: {
marginTop: theme.spacing(1),
},
}))
export default function App(props) {
const classes = useStyles()
return(
<AuthSecondaryButton
onClick={onClickSecondaryButton}
className={classes.secondaryButton}
>
Sign Up
</AuthSecondaryButton>
)

Resources