Styling a Select element from react-select - reactjs

I'm using a select element from the react-select library, and in my project I'm using styled-components.
I wanted to ask if it is possible for me to style it in my styles.ts file. if it's not possible, can you guys give any suggestions of how to do the styling??
Inside a React:FC
import Select from 'react-select'
...
const options = [
{ value: 'Income', label: 'Income' },
{ value: 'Expense', label: 'Expense' },
]
...
<Form>
<InputElement />
<Select options={options} />
</Form>

Yes, it is possible to provide your own custom styles, react-select provides an object-based approach for styling the Select component.
Reference to the docs
Here is a simple example,
const customStyles = {
option: (provided, state) => ({
...provided,
borderBottom: '1px dotted pink',
color: state.isSelected ? 'red' : 'blue',
padding: 20,
}),
control: () => ({
// none of react-select's styles are passed to <Control />
width: 200,
}),
singleValue: (provided, state) => {
const opacity = state.isDisabled ? 0.5 : 1;
const transition = 'opacity 300ms';
return { ...provided, opacity, transition };
}
}
const App = () => (
<Select
styles={customStyles} // pass the customStyles object to the styles prop
options={...}
/>
);
Select is very customizable through the keys provided to the custom style object.
One thing to remember is that each key will be a style function where the first argument will be the provided styles and the second argument will the state of select i.e isFocused, isSelected.
EDIT- While it is the suggested way of providing custom styles with the object-based approach. If you really want to style the Select component with styled-components, here is an example (you have to provide a classNamePrefix through prop and style based on classNames)
More on details on styling with classNames docs
import Select from 'react-select';
import styled from 'styled-components';
const SelectElement = styled(Select)`
.react-select-container {
// custom styles
}
.react-select__control {
// custom styles
}
.react-select__indicators {
// custom styles
}
`;
const MySelect = (props) => {
return (
<SelectElement classNamePrefix="react-select" options={options} {...props}/>
)
}

Yes, you can do it like this
import ReactSelect from 'react-select';
import styled from 'styled-components';
const ReactSelectStyled = styled(ReactSelect)`
// you have to provide custom styles through class names
// example
.react-select__option {
// custom styles
}
`;
Additionally, you can change the prefix of the class name (i.e "react-select" part in the class names) by providing the prefix through the classNamePrefix prop to the Select component.

Related

How to use 'classes' to customize compound components in Mui?

I am trying to override the Mui styles by using the classes prop.
For example, I would like to override the InputLabel color of the TextField component.
I would like to use one definition of makeStyles that will set all css rules, starting at the root (TextField) and overriding whatever I want in the hierarchy (for example, the InputLabel when focused), when passing it to the component in the classes prop.
How is it done?
import * as React from "react";
import TextField from "#mui/material/TextField";
import makeStyles from "#mui/styles/makeStyles";
const useStyles = makeStyles({
root: {
color: "yellow",
label: {
color: "brown"
}
}
});
export default function Input() {
const classes = useStyles();
return (
<TextField
classes={classes}
id="outlined-basic"
label="Outlined"
variant="outlined"
/>
);
}
Answer
import * as React from "react";
import TextField from "#mui/material/TextField";
import makeStyles from "#mui/styles/makeStyles";
const useStyles = makeStyles({
root: {
"& .MuiInputBase-input": {
color: 'red',
padding: "0.2rem"
},
},
});
export default function Input() {
const classes = useStyles();
return (
<TextField
InputProps={{ classes }}
/>;
);
}
codesandbox
The classes prop in MUI gives you access to the CSS Rule Names for a component. When you're using this prop, check the API spec for that component. The CSS Rule Names are at the bottom of the page.
https://mui.com/api/text-field/#css
For this component, there is only 1 rule available (root), so this will (I think) have the same effect as just using className.
What you probably want to do is use the InputProps prop instead. The Input component has way more CSS Rules you can target: https://mui.com/api/input/#css
So, I think you probably want to do this:
<TextField
InputProps={{ classes }}
id="outlined-basic"
label="Outlined"
variant="outlined"
/>
EDIT to help answer comment:
I don't think you need to target InputBase, as I believe you can target input instead. To target the input CSS Rule, just change the root key to input:
import * as React from "react";
import TextField from "#mui/material/TextField";
import makeStyles from "#mui/styles/makeStyles";
const useStyles = makeStyles({
input: {
color: 'red',
padding: "0.2rem"
},
});
export default function Input() {
const classes = useStyles();
return (
<TextField
InputProps={{ classes }}
/>;
);
}
The CSS rules in the docs are sensitive to the keys in the object you pass.
The best way I found is to use the Mui v5 sx property.
(makeStyles is deprecated - https://mui.com/guides/migration-v4/#2-use-tss-react)
(input signifies the rule in https://mui.com/api/input-base/#css)
import * as React from "react";
import TextField from "#mui/material/TextField";
export default function Input() {
const classes = useStyles();
return (
<TextField
sx={{
"& input":
{ padding: "0rem",color: "blue" }
}}
/>
);
}

How do I use Material UI theme colors inside a div?

I made a library that uses some Material UI components and they adapt their colors according to the theme provided by the project that installs them. I also want to use the "primary", "secondary" colors on a div because I want the background-color to adapt to the theme as well. Is there a way to do that?
In a Button the only thing I need to do is
<Button color="secondary"/>
But how do I do the equivalent to a div as well?
const MainContainer = styled.div`
background: secondary;
`;
How do I make this secondary color be the color of the theme of the parent project, like in the button?
I don't have any prior experience with style compononent. But as for materail-ui, you can apply color in 2 ways:-
using useTheme (inline use only - as far as I know), imported from material-ui/core/styles:-
import { useTheme } from 'material-ui/core/styles'
export const Demo = () => {
const theme = useTheme()
return (
<div style={{ backgroundColor: theme.palette.primary.main }}>Hi You!</div>
)
}
using makeStyles (you can solely use this without styled-component), imported from material-ui/core/styles
import { makeStyles } from 'material-ui/core/styles'
export const Demo = () => {
const classes = useStyles()
return (
<div className={classes.divStyle}>Hi You!</div>
)
}
const useStyles = makeStyles(theme => ({
divStyle: {
backgroundColor: theme.palette.primary.main
// or any color
// backgroundColor: 'red'
}
}))
You could get access to the colors which are present in the theme object by using useTheme hook.
https://material-ui.com/styles/api/#usetheme-theme

How to use custom props and theme with material-ui styled components API (Typescript)?

I'm attempting to use the Material UI styled components API to inject both a custom theme, and some props to a particular custom element.
I have either a custom theme or some props working, but not both together
Custom Theme
My custom theme is defined as follows in a separate file...
export interface ITheme extends Theme {
sidebar: SideBarTheme;
}
type SideBarTheme = {
// Various properties
};
const theme = createMuiTheme(
{
// Normal theme modifications
},
{
sidebar: {
// Custom theme modifications
},
} as ITheme
);
Which I then use with the Material-UI styled component API as follows....
const Profile = styled(Button)(({ theme }: { theme: ITheme }) => ({
backgroundColor: theme.sidebar.profile.backgroundColor,
paddingTop: 20,
paddingBottom: 20
}));
This works fine within my jsx with <Profile />.
Props
For props I'm essentially using an exact copy of the example here
interface MyButtonProps {
color: string;
}
const Profile = styled( ({ color, ...other }: MyButtonProps & Omit<ButtonProps, keyof MyButtonProps>) => (
<Button {...other} />
))({
backgroundColor: (props: MyButtonProps) => props.color,
paddingTop: 20,
paddingBottom: 20
});
This works fine within my jsx when using <Profile color="red"/>
How do I get both of these working together with typescript?
I literally tried combining them like below but the props don't pass down...
const Profile = styled( ({ color, ...other }: MyButtonProps & Omit<ButtonProps, keyof MyButtonProps>) => (
<Button {...other} />
))(({ theme }: { theme: ITheme }) => ({
backgroundColor: (props: MyButtonProps) => props.color,
color: theme.sidebar.profile.backgroundColor,
paddingTop: 20,
paddingBottom: 20
}));
Anything else I try just upsets TypeScript. The material-ui styled function is also too complicated for me to understand.
Many thanks,
This problem has also almost drove me crazy, however I've managed to make it work with this approach:
import React from 'react'
import { styled, Theme, withTheme } from '#material-ui/core/styles'
import { Box, BoxProps } from '#material-ui/core'
interface SidebarSectionProps {
padded?: boolean
theme: Theme
}
export const SidebarSectionComponent = styled(
(props: SidebarSectionProps & BoxProps) => <Box {...props} />
)({
marginBottom: ({ theme }: SidebarSectionProps) => theme.spacing(3),
paddingLeft: ({ theme, padded }: SidebarSectionProps) =>
padded ? theme.spacing(3) : 0,
paddingRight: ({ theme, padded }: SidebarSectionProps) =>
padded ? theme.spacing(3) : 0
})
export const SidebarSection = withTheme(SidebarSectionComponent)
For those who is using MUI5 and wondering how this could be done you can find an example in this github comment from material ui.
Copy of Typescript example:
const StyledComp = styled("div", {
shouldForwardProp: (prop) => prop !== "color" && prop !== 'myProp',
})<{ myProp?: boolean; color?: string }>(({ theme, myProp, color }) => ({
backgroundColor: myProp ? "aliceblue" : "red",
color,
padding: theme.spacing(1)
}));
<StyledComp myProp color="red" /> // typed safe
I'm not sure it makes sense to use styled-components or the material styled HOC because those are better for setting fixed styles which don't depend on Props.
But you can set the styles that you want on through the style prop of the Button component.
Here's a solution that seems to work:
interface AddedProps {
theme: Theme;
color: string;
};
type InnerProps = AddedProps & Omit<ButtonProps, keyof AddedProps>
const InnerProfile = ({color, theme, ...other}: InnerProps) => (
<Button
{...other}
style={{
...other.style,
paddingTop: 20,
paddingBottom: 20,
backgroundColor: color,
color: (theme as MyTheme).sidebar?.profile?.backgroundColor,
}}
/>
)
export const Profile = withTheme( InnerProfile );
We say that our Profile needs two AddedProps: the color and the theme. We write InnerProfile assuming that those props exist. Then in a separate step we apply the withTheme HOC so that the theme prop will be set. The color prop is required and must be set by you when using <Profile />.
Now for this wonky craziness:
color: (theme as MyTheme).sidebar?.profile?.backgroundColor
What's happening is that withTheme knows that it injects a theme but it doesn't know that it injects your specific theme so typescript doesn't know that the theme has a property sidebar at all, since that's a custom property that you added. You need to tell typescript "assume this theme has the properties of MyTheme" by doing (theme as MyTheme). You can get that type MyTheme by using typeof on the object where you created your custom theme.
Since I don't have access to your custom theme object, what I did was define an interface that has the needed property path, but with everything optional. That looks like:
interface MyTheme extends Theme {
sidebar?: {
profile?: {
backgroundColor?: string;
}
}
}
And I used typescript ?. notation when accessing sidebar?.profile?.backgroundColor to avoid the "object is possibly undefined" error.

Style a component's [aria-checked="true"] using Material UI's makeStyle

I have a check box (not a Material-UI checkbox) that I'd like to style using it's aria-checked="true" attribute via makeStyles. I see in the Material-UI docs that you can style pseudo selectors as such:
'&:hover': { /* … */ },
But I haven't been able to make this work for the aria attribute? Is this possible? If so, how?
The syntax for attribute selectors is largely the same as in CSS. & is used to refer to the generated class (classes.myCheckboxStyles in my example below) and then further selectors can be added within the quotes (e.g. "&[aria-checked=true]").
Below is a working example demonstrating the syntax:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
myCheckboxStyles: {
border: "1px black solid",
color: "white",
"&[aria-checked=true]": {
backgroundColor: "blue"
}
}
});
export default function Checkboxes() {
const classes = useStyles();
const [checked, setChecked] = React.useState(false);
return (
<div>
<span
onClick={() => setChecked(!checked)}
aria-checked={checked}
className={classes.myCheckboxStyles}
>
X
</span>
</div>
);
}
I've tried to use aria-checked="true" to activate MUI checkbox, but it doesn't work. So, in my view, you should try using onMouseEnter to activate MUI checkbox. You can try this:
import React from "react";
import Checkbox from "#material-ui/core/Checkbox";
export default function Checkboxes() {
const [checked, setChecked] = React.useState(false);
const handleChange = event => {
setChecked(event.target.checked);
};
return (
<div>
<Checkbox
checked={checked}
onMouseEnter={() => setChecked(true)}
onChange={handleChange}
inputProps={{ "aria-label": "primary checkbox" }}
/>
</div>
);
}

Correct way to target and style specific child elements in Material-ui wrapper components?

What is the correct/suggested way to target and style specific child elements in Material-ui wrapper components using makeStyles()? Do we use the class selectors?
e.g. Targeting the input element of a TextField component I use & .MuiInput-input
import { makeStyles} from '#material-ui/core/styles';
const useStyles = makeStyles(theme => ({
foo: {
'& .MuiInput-input': {
backgroundColor: 'red'
}
}
});
export default function () {
const classes = usePageStyles();
return (<div>
<TextField
id="search"
label="Search"
placeholder="Search"
className={classes.x}
/>
</div>);
};
I know that there are a lot of methods to style components in Material-UI, which is why I am a bit confused which is which. So, I just want to know the standard way to target the child elements. I saw examples in the docs using '& p' - does that mean that there is no Material-UI specific way? We just use basic css selectors?
I'd suggest passing in InputProps with an object to the TextField.
Something like:
const InputProps = {
className: classes.input,
color: 'primary'
}
Then pass it into TextField:
<TextField
InputProps={InputProps}
>

Resources