I am using a Material UI React component called TextareaAutosize:
<TextareaAutosize
minRows={2}
style={resize: 'none'}
defaultValue={<span style={{fontSize: "20px", color: "blue"}}>Content Body</span>}
/>
Instead of getting Content Body in the TextareaAutosize component, I'm getting this as the default value:
How do I add styling to the defaultValue?
Edit code on Stack Blitz: https://stackblitz.com/edit/react-fnx6we?file=demo.js
EDIT: For clarification, I want ONLY the defaultValue to have the styling I applied. When the user starts typing or removes the defaultValue and starts typing, the styling of the defaultValue should NOT be applied.
defaultValue parameter accepts String values only. Use parameter style to define additional styling. Or use jss like styling for components (check #mui/styles) EDIT: to change styling of the element "on the fly" you will need to use additional variables and functions. Check demo on code on Stack Blitz.
import React, { useState } from 'react';
import TextareaAutosize from '#mui/material/TextareaAutosize';
import { makeStyles } from '#mui/styles';
const useStyles = makeStyles({
textAreaWithStyle: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
border: 0,
borderRadius: 3,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
color: 'white',
height: 48,
padding: '0 30px',
fontSize: '20px',
color: 'blue',
resize: 'none',
},
textAreaWithoutStyle: {
resize: 'none',
},
});
export default function MaxHeightTextarea() {
const classes = useStyles();
const [valueOfInput, setValueOfInput] = useState('Default Text');
const returnStyleBasedOnInput = () => {
if (valueOfInput === 'Default Text') {
return classes.textAreaWithStyle;
} else {
return classes.textAreaWithoutStyle;
}
};
const checkIfDefaultValueInTextAreaAndRemooveIt = () => {
if (valueOfInput === 'Default Text') {
setValueOfInput('');
}
};
const onInputChange = (e) => {
setValueOfInput(e.target.value);
};
return (
<TextareaAutosize
maxRows={4}
className={returnStyleBasedOnInput()}
value={valueOfInput}
onChange={onInputChange}
onClick={checkIfDefaultValueInTextAreaAndRemooveIt}
/>
);
}
Edit code on Stack Blitz: https://stackblitz.com/edit/react-fnx6we-3vdn7i?file=demo.js
Related
I need to have the accordion component that will change over a state when user clicks on the icon.
When user clicks on the icon, the icon and color of the title should get changed and list of links should display.
So far I managed to add onClick option to the component but what will be the best approach to achieve the result of a list displaying over a click?
How to make the icon change over click and display a list with storybook?
Could you please kindly give some advise?
Any help would be appreciated.
I already added two options for the icon, so I think I can add somehow a state to it and make it display on storybook, but not really sure how :(
Here is the component:
import { string, oneOf, func, bool } from "prop-types"
import Icon, { icons } from "design-system/components/icon"
import * as Styled from "./Button.styled"
const Button = ({
href,
text,
iconStart,
iconEnd,
variant,
color,
size,
active,
onClick,
}) => (
<Styled.Component
as={href ? `a` : `button`}
variant={variant}
color={color}
size={size}
href={href}
onClick={onClick}
>
{iconStart && (
<Styled.Icon>
<Icon name={iconStart} size={size} />
</Styled.Icon>
)}
<Styled.Text variant={variant} color={color} active={active}>
{text}
</Styled.Text>
{iconEnd && (
<Styled.Icon>
<Icon name={iconEnd} size={size} />
</Styled.Icon>
)}
</Styled.Component>
)
Button.propTypes = {
text: string.isRequired,
href: string,
iconStart: oneOf(Object.keys(icons)),
iconEnd: oneOf(Object.keys(icons)),
variant: oneOf(["fill", "border", "text", "textLine"]),
color: oneOf(["primary", "black", "white"]),
size: oneOf(["small", "medium", "large"]),
active: bool,
onClick: func,
}
Button.defaultProps = {
href: null,
iconStart: null,
iconEnd: null,
variant: "fill",
color: "primary",
size: "medium",
active: null,
onClick: null,
}
export default Button
Here are the styles:
import styled from "#emotion/styled"
import { css } from "#emotion/react"
import theme from "design-system/theme"
const sizes = {
small: {
typography: theme.typography.desktop.bodySmall,
padding: "8px 32px",
},
medium: {
typography: theme.typography.desktop.h5,
padding: "10px 40px",
},
large: {
typography: theme.typography.desktop.h4,
padding: "12px 48px",
},
}
const colors = {
primary: {
mainColor: theme.colors.primary[500],
filledText: theme.colors.neutrals[100],
},
black: {
mainColor: theme.colors.grey[600],
filledText: theme.colors.neutrals[100],
},
white: {
mainColor: theme.colors.neutrals[100],
filledText: theme.colors.primary[300],
},
}
export const Component = styled.a`
text-align: center;
border-radius: 10px;
padding: 19px;
position: relative;
color: ${({ theme }) => theme.colors.grey[600]};
background-color: ${({ theme }) => theme.colors.complementary[100]};
`
export const Text = styled.span`
${({ variant }) =>
variant === "textLine" &&
css`
text-decoration: underline;
`}
${({ active, variant, color }) =>
active &&
variant === "text" &&
css`
border-bottom: 2px solid ${colors[color].mainColor};
`}
`
export const Icon = styled.span`
display: inline-flex;
align-items: center;
justify-content: center;
`
and storybook:
import { Meta, Canvas, Story, ArgsTable } from "#storybook/addon-docs"
import Button from "design-system/components/button"
import Icon from "design-system/components/icon"
<Meta title="Components/Button" component={Button} />
# Button
<Canvas>
<Story
name="Overview - button icon end"
args={{
text: "O nas",
iconEnd: "arrowDown",
variant: "fill",
size: "medium",
}}
>
{Template.bind()}
</Story>
</Canvas>
<ArgsTable />
export const Template = (args) => <Button {...args} />
I use makeStyles to style a custom card but the MUI default styles are overriding them, when I use !important my styles are applying otherwise they are getting overridden.
const useStyles = makeStyles({
'dashboard-card': {
boxSizing: 'border-box',
borderRadius: '20px',
boxShadow:
'0px 4px 4px rgba(50, 50, 71, 0.08), 0px 4px 8px rgba(50, 50, 71, 0.06)',
},
});
type DashboardCardProps = {
children: JSX.Element | JSX.Element[];
className?: string;
};
const DashboardCard = ({ children, className }: DashboardCardProps) => {
const classes = useStyles();
return <Card className={`${className} ${classes['dashboard-card']}`}>{children}</Card>;
};
export default DashboardCard;
Is there any way how can I get around this, is it possible to remove the default stylings from the theme?
const theme = createTheme({
palette: {
primary: {
light: '#21B8F9',
main: '#103B66',
dark: '#000032',
},
},
components: {
MuiCard: {
styleOverrides : {
root: {}
}
},
MuiPaper: {
styleOverrides: {
root: {}
}
}
},
typography: {
fontFamily: ['Source Sans Pro', 'Noto Sans HK'].join(','),
},
});
What is the best way to create variants using styled components? Heres what i am currently doing.
const ButtonStyle = styled.button`
padding:8px 20px;
border:none;
outline:none;
font-weight:${props => props.theme.font.headerFontWeight};
font-size:${props => props.theme.font.headerFontSize};
display:block;
&:hover{
cursor:pointer;
}
${({ variant }) =>
variant == 'header' && css`
background-color:${props => props.theme.colors.lightblue};
color:${({ theme }) => theme.colors.white};
&:active{
background-color:${props => props.theme.colors.blue}
}
`
}
${({ variant }) =>
variant == 'white' && css`
background-color:white;
color:${({ theme }) => theme.colors.lightblue};
&:active{
color:${props => props.theme.colors.blue}
}
`
}
`;
I cannot tell if this is the standard way of doing things.
I have also been using other components as bases to create other components from while changing a few things
eg
const InnerDiv = styled(otherComponent)`
position: unset;
background-color: red;
overflow-x: hidden;
display: flex;
`;
Which is the better approach? Are there any better alternatives?
Inspired by previous solutions, I want to share what I came up with:
import styled, { css, DefaultTheme } from 'styled-components';
const variantStyles = (theme: DefaultTheme, variant = 'primary') =>
({
primary: css`
color: ${theme.colors.light};
background: ${theme.colors.primary};
border: 1px solid ${theme.colors.primary};
`,
}[variant]);
const Button = styled.button<{ variant: string }>`
padding: 1rem;
font-size: 0.875rem;
transition: all 0.3s;
cursor: pointer;
${({ theme, variant }) => variantStyles(theme, variant)}
&:active {
transform: translateY(1.5px);
}
`;
export default Button;
For now it contains only primary and its the default one, by you can add more variants by adding new object to variantStyles object
Then you can use it by passing the variant as a prop or keep the default by not passing any variant.
import { Button } from './HeroSection.styles';
<Button variant="primary">Start Learning</Button>
This is just my opinion:
I don't think we can do anything very different from what you did.
A different way that I thought, would be to create an options object to map the possibilities of the variant, like this:
const variantOptions = {
header: {
backgroundColor: theme.colors.lightblue,
color: theme.colors.white,
active: theme.colors.blue,
},
white: {
backgroundColor: "white",
color: theme.colors.lightblue,
active: theme.colors.blue,
},
};
And use it in your style component like this:
const ButtonStyle = styled.button`
padding: 8px 20px;
border: none;
outline: none;
font-weight: ${(props) => props.theme.font.headerFontWeight};
font-size: ${(props) => props.theme.font.headerFontSize};
display: block;
&:hover {
cursor: pointer;
}
${({ variant }) =>
variant &&
variantOptions[variant] &&
css`
background-color: ${variantOptions[variant].backgroundColor};
color: ${variantOptions[variant].color};
&:active {
color: ${variantOptions[variant].active};
}
`}
`;
And all of this buttons will work:
<ButtonStyle variant="*wrong*">Button</ButtonStyle>
<ButtonStyle variant="header">Button</ButtonStyle>
<ButtonStyle variant="white">Button</ButtonStyle>
<ButtonStyle>Button</ButtonStyle>
When dealing with Styled Component variants here is what I like to do to keep things organised and scalable.
If the variants are stored within the same file I am using the inheritance properties:
const DefaultButton = styled.button`
color: ${(props) => props.theme.primary};
`;
const ButtonFlashy = styled(DefaultButton)`
color: fuchsia;
`;
const ButtonDisabled = styled(DefaultButton)`
color: ${(props) => props.theme.grey};
`;
If if we are talking about a reusable components I would use this technique:
import styled from 'styled-components';
// Note that having a default class is important
const StyledCTA = ({ className = 'default', children }) => {
return <Wrapper className={className}>{children}</Wrapper>;
};
/*
* Default Button styles
*/
const Wrapper = styled.button`
color: #000;
`;
/*
* Custom Button Variant 1
*/
export const StyledCTAFushia = styled(StyledCTA)`
&& {
color: fuchsia;
}
`;
/*
* Custom Button Variant 2
*/
export const StyledCTADisabled = styled(StyledCTA)`
&& {
color: ${(props) => props.theme.colors.grey.light};
}
`;
export default StyledCTA;
Usage:
import StyledCTA, { StyledCTADisabled, StyledCTAFushia } from 'components/StyledCTA';
const Page = () => {
return (
<>
<StyledCTA>Default CTA</StyledCTA>
<StyledCTADisabled>Disable CTA</StyledCTADisabled>
<StyledCTAFushia>Fuchsia CTA</StyledCTAFushia>
</>
)
};
Read more about this in the blog posts I created on the subject here and there.
There are many ways to do this. one simple way is to use the package called Styled-components-modifiers. documentation is simple and straightforward.
https://www.npmjs.com/package/styled-components-modifiers
Simple usage example:
import { applyStyleModifiers } from 'styled-components-modifiers';
export const TEXT_MODIFIERS = {
success: () => `
color: #118D4E;
`,
warning: () => `
color: #DBC72A;
`,
error: () => `
color: #DB2A30;
`,
};
export const Heading = styled.h2`
color: #28293d;
font-weight: 600;
${applyStyleModifiers(TEXT_MODIFIERS)};
`;
In the Component - import Heading and use modifier prop to select the variants.
<Heading modifiers='success'>
Hello Buddy!!
</Heading>
Styled components are usually used with Styled system that supports variants and other nice features that enhance Styled components. In the example below Button prop variant automatically is mapped to keys of variants object:
const buttonVariant = ({ theme }) =>
variant({
variants: {
header: {
backgroundColor: theme.colors.lightblue,
color: theme.colors.white,
active: theme.colors.blue,
},
white: {
backgroundColor: 'white',
color: theme.colors.lightblue,
active: theme.colors.blue,
},
},
})
const Button = styled.button`
${(props) => buttonVariant(props)}
`
Styled System Variants: https://styled-system.com/variants
Use the variant API to apply styles to a component based on a single prop. This can be a handy way to support slight stylistic variations in button or typography components.
Import the variant function and pass variant style objects in your component definition. When defining variants inline, you can use Styled System like syntax to pick up values from your theme.
// example Button with variants
import styled from 'styled-components'
import { variant } from 'styled-system'
const Button = styled('button')(
{
appearance: 'none',
fontFamily: 'inherit',
},
variant({
variants: {
primary: {
color: 'white',
bg: 'primary',
},
secondary: {
color: 'white',
bg: 'secondary',
},
}
})
)
I canĀ“t style the Outline Select component with the properties I want when using Material UI with react, how can override default styles?
I have used withStyles but I can't achieve the expected look and feel.
For example if I change the border using a custom Input in the Select, then the Label doesn't work as expected, the border and the label touch instead of the label like floating.
import { createStyles, makeStyles, withStyles } from '#material-ui/core/styles';
import OutlinedInput from '#material-ui/core/OutlinedInput';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
export const StyledSelect = ({ name, value, onChange, items }) => {
const classes = useStyles();
const inputLabel = React.useRef<HTMLLabelElement>(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {
setLabelWidth(inputLabel.current!.offsetWidth);
}, []);
return (
<FormControl variant="outlined" />
<InputLabel
ref={inputLabel}
htmlFor={name}
>
{name}
</InputLabel>
<Select
value={value || ''}
onChange={onChange}
input={<CustomInput labelWidth={labelWidth} />}
>
{items.map(item => {
return (
<MenuItem key={item.key} value={item}>
{item.label}
</MenuItem>
);
})}
</Select>
</FormControl>
);
};
const CustomInput = withStyles(theme => ({
root: {
'label + &': {
/* marginTop: theme.spacing(3), */
},
},
/* label: {
width: '',
}, */
input: {
'borderRadius': 4,
'position': 'relative',
/* 'backgroundColor': theme.palette.background.paper, */
'border': '2px solid #ced4da',
/* 'fontSize': 16, */
/* 'transition': theme.transitions.create(['border-color', 'box-shadow']), */
// Use the system font instead of the default Roboto font.
'fontFamily': [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(','),
'&:hover': {
border: '2px solid red',
borderRadius: 4,
},
'&:focus': {
border: '2px solid #ced4da',
borderRadius: 4,
borderRadius: 4,
borderColor: "#80bdff",
boxShadow: "0 0 0 0.2rem rgba(0,123,255,.25)"
},
},
}))(OutlinedInput);
I expect to style only what I need and don't break the functionality of the OutlineSelect component.
When you click an input field in material UI the class names is changed and a different style is applied to the label field.
More specifically the class .MuiInputLabel-shrink is added to the label element. If you want to target this styling, you must reference this class in your withStyles()
See the imput-label API here:
https://material-ui.com/api/input-label/#main-content
I tried it like this but it doesn't do anything:
const myToast = () => (
<div style={{backgroundColor: myColors.green}}>
...some text content...
</div>
)
Then in App.js
class App extends Component {
showMyToast = () => {
toast(<MyToast />, {
closeOnClick: false,
toastId: 'my_toast',
autoClose: true,
closeButton: false,
position: toast.POSITION.BOTTOM_CENTER,
className: 'toast'
})
}
}
I'm seeing a white toast with my text on it.
Easiest Solution
The easiest solution to adjust the BG of Toastify, or in fact any styles would be to use the ToastContainer props toastStyle: which takes in JSX attributes.
After importing the necessary packages , while adding the ToastContainer component , just pass in the toastStyle prop and you shall be good to go.
<ToastContainer toastStyle={{ backgroundColor: "crimson" }} />
Based on #Laurens answer I found the pattern in the code sandbox very useful. Here's what I did to get the notification shown below
First, I mounted my toast container at the root of my App, inside my App component
import React from 'react';
import { Provider } from 'react-redux';
import { ToastContainer } from 'react-toastify';
import store from './redux/store';
import Routes from './Routes';
const App = () => {
return (
<Provider store={store}>
<ToastContainer
autoClose={2000}
position="top-center"
className="toast-container"
toastClassName="dark-toast"
/>
<Routes />
</Provider>
);
};
Then, for each notification style, I defined a series of CSS styles. The components looked like so
// customToast.js
import { toast } from 'react-toastify';
import { css } from 'glamor';
const customToast = {
success(msg, options = {}) {
return toast.success(msg, {
...options,
className: 'toast-success-container toast-success-container-after',
progressClassName: css({
background: '#34A853',
}),
});
},
error(msg, options = {}) {
return toast.error(msg, {
...options,
className: 'toast-error-container toast-error-container-after',
progressClassName: css({
background: '#EE0022',
}),
});
},
info(msg, options = {}) {
return toast.info(msg, {
...options,
className: 'toast-info-container toast-info-container-after',
progressClassName: css({
background: '#07F',
}),
});
},
};
export default customToast;
To use these just do import customToast from 'customToast.js'. Now you can use customToast.success, customToast.error etc
The style for the success notification is shown below
.toast-success-container {
color: #000 !important;
border-radius: 8px !important;
background: #FFFFFF !important;
border: 1px solid #34A853 !important;
box-shadow: 0px 1px 5px rgba(248, 175, 175, 0.1) !important;
}
.toast-success-container-after {
overflow: hidden;
position: relative;
}
.toast-success-container-after::after{
top: 0;
left: 0;
content: '';
width: 7px;
height: 100%;
position: absolute;
display: inline-block;
background-color: #34A853;
}
You'll also notice that I had to stick a series of !importants in my css
The easiest solution is setting the theme property, as mentioned in the docs.
You can:
Set theme globally
//Set the theme globally
<ToastContainer theme="colored" />
Or define per toast
// define per toast
toast.info("Display a blue notification of type info", { theme: "colored" });
This changes the background color based on the toast type (error, warning, info etc).
Hopefully this helps anyone in future.
You can use Glamor for easily adjusting simple things like toast background color.
This example displays a simple toast with a green background using glamor.
toast("Hello!", {
className: css({
background: "#00FF00 !important"
})
});
If the requirements are more complex you can implement your own styles globally as per this example.
You can simply override it in CSS if the color is a hardcoded value. However, you could also use Helmet if the color needs to be variable e.g. as an app theme color that can change through user preferences or something. Looking at your example, you would include
<Helmet
style={[
{
cssText: `
.Toastify__toast--success {
background: ${customColor} !important;
}
`,
},
]}
/>
The customColor variable would be pulled out of your store and could be updated on the fly, giving you a custom toast background color.
I think this is the simplest solution.
1.install glamorous using following link https://glamorous.rocks/basics/#installation
2.after that import css to your js file like this..
import { css } from 'glamor';
3.after that give your own style to the toast popup like this..
toast.configure({
autoClose:10000,
draggable: true,
hideProgressBar: true,
position: toast.POSITION.TOP_CENTER,
toastClassName: css({
fontSize: '18px !important',
backgroundColor: '#da1c36 !important',
padding: '15px !important'
}),
});
What about (for version 9.1.1):
toast.info(msg, {
position: 'top-right',
autoClose: 15000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: 0,
progressStyle: { background: '#E8DFD0' },
theme: 'colored',
style: { background: '#766852' },
});
};
**If you want change the without CSS.
notify = () => this.toastId = toast.error('error') { error: "error", info: "info", success: "success", warning: "warning", } Use like this Above
OtherWise .
Toastify__toast--error{ background-color: red; }**