I know there's a similar question but what I need is different.
I have declared the common styles that my button will be using and I'm using a function with a switch statement that has different properies for different buttons that I will be using in other pages and for one case I need the border-radius and padding different from the common one, how can I update(or replace) the value without using !important or && {.
Here's the code
import { TTheme } from 'src/styles/Themes/Theme';
import styled, { css, FlattenSimpleInterpolation } from 'styled-components';
const getVariantCSS = <T extends TTheme>(props: T): FlattenSimpleInterpolation => {
const { theme } = props;
switch (props.variant) {
case 'secondary':
return css`
background-color: ${theme.colors.white};
color: ${theme.colors.primary};
border: ${theme.borders.solid1} ${theme.colors.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverLight};
border: ${theme.borders.none};
box-shadow: ${theme.boxShadows.primary};
}
`;
case 'half':
return css`
color: ${theme.colors.white};
background-color: ${theme.colors.primary};
&& {
border-radius: ${theme.radius.half};
padding: ${theme.paddings.small};
}
border: ${theme.borders.solid2} ${theme.colors.white};
`;
case 'dark':
return css`
background-color: ${theme.colors.tertiary};
color: ${theme.colors.primary};
border: ${theme.borders.solid1} ${theme.colors.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverDark};
box-shadow: ${theme.boxShadows.primary};
filter: ${theme.filter.brightness};
border: ${theme.borders.none};
opacity: ${theme.opacity.default};
}
`;
default:
return css`
background-color: ${theme.colors.primary};
color: ${theme.colors.white};
border: ${theme.borders.none};
box-shadow: ${theme.boxShadows.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverLight};
}
`;
}
};
export const StyledButton = styled.button`
${getVariantCSS}
width: 100%;
height: 100%;
padding: ${(props) => props.theme.paddings.medium};
display: ${(props) => props.theme.content.display.flex};
flex-direction: ${(props) => props.theme.content.flexDirection.row};
justify-content: ${(props) => props.theme.content.justifyContent.center};
align-items: ${(props) => props.theme.content.alignItems.center};
flex-grow: ${(props) => props.theme.content.flexGrow.one};
border-radius: ${(props) => props.theme.radius.button};
I suggest using the cascade. just place "getVariantsCSS" below the main styles and then the desired styles will be applied and then "important" and "&&" is not needed.
https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance#the_cascade
export const StyledButton = styled.button`
width: 100%;
height: 100%;
padding: ${(props) => props.theme.paddings.medium};
display: ${(props) => props.theme.content.display.flex};
flex-direction: ${(props) => props.theme.content.flexDirection.row};
justify-content: ${(props) => props.theme.content.justifyContent.center};
align-items: ${(props) => props.theme.content.alignItems.center};
flex-grow: ${(props) => props.theme.content.flexGrow.one};
border-radius: ${(props) => props.theme.radius.button};
${getVariantCSS}
`
Related
For whatever reason, the buttons (defined by AboutItem) are displaying light blue backgrounds when I hover over them. I want to make it #282828.
In a separate file I define some styled components for Buttons:
export const Button = styled.button`
display: inline-block;
font-size: 1em;
margin: 1em;
padding: 0em 1em;
`;
export const InfoButton = styled(Button)`
color: grey;
&:hover {
background-color: lightblue;
}
`;
which I then use:
interface AboutNavProps {
selected: boolean;
}
const AboutItem = styled(InfoButton) <AboutNavProps>`
color: grey;
background-color: ${props => props.selected ? "#282828" : "transparent"};
text-align: center;
&:hover {
background-color: #282828;
}
`;
export function AboutNavbar() {
const router = useRouter()
useEffect(() => {
router.prefetch("/method");
}, [])
return (
<AboutNav aria-label="Navbar">
<AboutItem as="a" href="method" selected={router.pathname == "/method"}>How It Works</AboutItem>
<AboutItem as="a" href="about" selected={router.pathname == "/about"}>About</AboutItem>
<Logo />
</AboutNav>
);
}
Is there a reason for this? I don't understand why the light blue overrides the color I define for the hover.
import styled from '#emotion/styled';
type ColorProps = {
Coloured: boolean,
}
const BoxStyled = styled.div`
${(props:ColorProps) =>
props.Coloured ? {
background: "#304f8f",
border: "1.85px solid #304f8f",
color: "white",
width: "4rem",
height: "2.5rem",
padding:"0 11px"
} :
{
border: "1.98px solid #2c8090",
width: "4rem",
height: "2.5rem",
padding:"0 11px"
}
}`
here in BoxStyled I don't want to write width: "4rem", height: "2.5rem", padding:"0 11px" twice how do I achieve this ?
Use css to make a variable of style.
import { css } from 'styled-components'
const reuse = css`
width: 4rem;
height: 2.5rem;
padding: 0 11px;
`
const StyleA = styled.div`
background-color: black;
${reuse}
`
const StyleB = styled.div`
background-color: red;
${reuse}
`
Check this for more information.
You can define the main style and when needed to change overwrite new style.
import styled from '#emotion/styled';
type ColorProps = {
Coloured: boolean,
}
const BoxStyled = styled.div`
border: "1.98px solid #2c8090",
width: "4rem",
height: "2.5rem",
padding:"0 11px"
${(props:ColorProps) =>
props.Coloured && {
background: "#304f8f",
border: "1.85px solid #304f8f",
color: "white",
}
}`
I have a simple colored button in my app that needs to change color based on some UI state:
const StyledButton = styled.button`
& {
border: 0;
color: white;
cursor: pointer;
}
&:hover {
background-color: ${(props) => props.theme.hoverColor};
}
&.base {
background-color: ${(props) => props.theme.baseColor};
}
&.selected {
background-color: ${(props) => props.theme.selectedColor};
}
&&.danger:hover {
background-color: ${(props) => props.theme.dangerColor};
}
&.disabled {
background-color: ${(props) => props.theme.disabledColor};
}
`;
Previously I was using CSS Modules to make sure classes would not "leak" to other styles and I have obtained the styled component by essentially a 1-to-1 translation.
.Button {
border: 0;
color: white;
cursor: pointer;
}
.Button:hover {
background-color: var(--hover-color);
}
.Button.base {
background-color: var(--base-color);
}
.Button.selected {
background-color: var(--selected-color);
}
.Button.Button.danger:hover {
background-color: var(--danger-color);
}
.Button.disabled {
background-color: var(--disabled-color);
}
I like the theming support in Styled Components, but I dislike how now my "local" classes are no longer local to the component. I consider this a significant tradeoff.
Am I missing the correct way of implementing multiple variants of a component?
At the moment I have found two solutions:
The first is to calculate by hand the end result and avoid any classes
const StyledButton = styled.button`
& {
border: 0;
color: white;
cursor: pointer;
}
${(props) =>
props.isBase &&
css`
&,
&:hover {
background-color: ${(props) => props.theme.baseColor};
}
`}
${(props) =>
props.selectedColor &&
css`
&,
&:hover {
background-color: ${(props) => props.theme.selectedColor};
}
`}
${(props) =>
props.isDisabled &&
css`
&,
&:hover {
background-color: ${(props) => props.theme.disabledColor};
}
`}
${(props) =>
props.isDanger &&
css`
& {
background-color: ${(props) => props.theme.dangerColor};
}
&:hover {
background-color: ${(props) => props.theme.dangerColor};
}
`}
`;
which works but is quite ugly
and the other is to split the StyledButton into many components:
const StyledButton = styled.button`
& {
border: 0;
color: white;
cursor: pointer;
background-color: ${(props) => props.theme.baseColor};
}
`;
const StyledSelectedButton = styled(StyledButton)`
& {
background-color: ${(props) => props.theme.selectedColor};
}
`;
const StyledDisabledButton = styled(StyledButton)`
& {
background-color: ${(props) => props.theme.disabledColor};
}
`;
const StyledDangerButton = styled(StyledButton)`
& {
background-color: ${(props) => props.theme.baseColorColor};
}
&&:hover {
background-color: ${(props) => props.theme.dangerColor};
}
`;
Which is better but I am afraid of an eventual combinatorial explosion once more complex states are involved (a selected danger component) or more pseudoclasses are involved.
Moreover if the button in question had a state (e.g. a click counter) changing style would destroy the state.
I cannot think of a solution around this problem.
i wanted to add border property only when isOpen condition true using styled components and react.
below is my code,
const Wrapper = styled.div<{ $isOpen: boolean }>`
border: 1px solid black;
display: flex;
`;
How to apply border only when isOpen is true?
could someone help me with this. thanks.
You can try like this:
const Wrapper = styled.div`
display: flex;
${({isOpen}) =>
isOpen &&
css`
{
border: 1px solid black;
}`
}
`;
Grabbing an example from the home page of styled-components:
import styled, { css } from 'styled-components'
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
${props =>
props.primary &&
css`
background: palevioletred;
color: white;
`};
`
How you would use it in the react renderer:
render(
<Container>
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
</Container>
);
Which is more optimized and why?
I hear that the css method from Styled-component is pretty expensive but I'm wondering if the multiple nested ${(prop) => {}} is more expensive than the single fn with the css method used inside.
Approach 1
const Foo = styled.div`
border-radius: 50%;
display: flex;
width: ${(props) => props.size};
height: ${(props) => props.size};
color: ${(props) => props.bgColor};
background-color: ${(props) => props.bgColor};
`;
vs
Approach 2
const Bar = styled.div`
border-radius: 50%;
display: flex;
${(props) => {
return css`
width: ${props.size};
height: ${props.size};
color: ${props.bgColor};
background-color: ${props.bgColor};
`;
}}
`;
Performance difference should be negligible. The only optimization Styled Components would make is if your styles were static (with no interpolations).
Note that styled.div or any other of the Styled CSS methods already do the same work as css. And these methods accept functions as arguments (instead of interpolated strings). So you can take it a step further and do this:
const Baz = styled.div((props) => css`
border-radius: 50%;
display: flex;
width: ${props.size};
height: ${props.size};
color: ${props.bgColor};
background-color: ${props.bgColor};
`);