const Button = styled.button`
display: inline-block;
width: 300px;
background-color: black;
`
const ButtonHref = styled.a`
${Button}
`
So I have two styled-components. I want to inherit 'Button' styles but create another tag. I use react-emotion. How can I do this?
There are a few options here, using composition, styled components, or with props. The second option is probably what you want, but I've provided two other options as well.
1. Using composition
const baseButton = css`
color: white;
background-color: black;
`
const fancyButton = css`
background-color: red;
`
render() {
return (
<div>
<button css={baseButton}></button>
<button css={[baseButton, fancyButton]}></button>
</div>
)
}
The second button will have the baseButton and specialButton styles.
Or...
const baseButton = css`
color: white;
background-color: black;
`
const fancyButton = css`
${baseButton};
background-color: red;
`
render() {
return (
<div>
<button css={baseButton}></button>
<button css={fancyButton}></button>
</div>
)
}
2. Using styled components
const Button = styled.button`
color: white;
background-color: black;
`
const Fancy = styled(Button)`
background-color: red;
`
render() {
return (
<div>
<Button>Button</Button>
<Fancy>Fancy</Fancy>
</div>
)
}
This works for any component that accepts the className prop, which button does.
3. Using props
const Button = styled.button`
color: white;
background-color: ${props => props.fancy ? 'red' : 'black'};
`
render() {
return (
<div>
<Button>Button</Button>
<Button fancy>Fancy</Button>
</div>
)
)
If you just want an a that has the exact styles as your Button then you can do <Button as=“a” />
You could also add some custom css like this:
const ButtonBase = styled.button`
// some css here
`
const SmallButtonCustom = `
// some css here
`
const SmallButton = styled(ButtonBase)`
${SmallButtonCustom};
`
Related
NavStyles.js
import styled from 'styled-components';
export const Nav = styled.navwidth: 100%; ;
export const NavMenuMobile = styled.ul`
height: 80px;
.navbar_list_class {
font-size: 2rem;
background-color: red;
}
${props => props.navbar_list_props && `
font-size: 2rem;
background-color: gray;
`}
`;
Navbar.js
import React from 'react'
import {Nav, NavMenuMobile} from "./NavStyles";
const Navbar = () => {
return (
<Nav>
{/* work no problem */}
<NavMenuMobile navbar_list_props>Nav Bar props</NavMenuMobile>
{/* not work How to use..? */}
<NavMenuMobile className="navbar_list_class">Nav Bar class</NavMenuMobile>
</Nav>
)
}
export default Navbar
<Nav>
<NavMenuMobile className={navbar_list_props}>Nav Bar props</NavMenuMobile>
</Nav>
Try This
Looks like you are setting styles for the children within NavMenuMobile with the class "navbar_list_class".
Should work with &.navbar_list_class
export const NavMenuMobile = styled.ul`
height: 80px;
&.navbar_list_class {
font-size: 2rem;
background-color: red;
}
`;
I have a Menu/Tabs React component I'm building that I've set up to receive a combination of both an SVG and a string of text as the title prop in order to display as the tab name.
The issue I'm having is that I have an active class that colors the active tab text blue, but not the SVG which remains black.
Desired Behavior: Have active class CSS stylings applied to both text and SVG elements so that they are both blue when active and both black when they are inactive
Current Behavior: Active class stylings are applied to the text but not the SVG. When tab is active text turns blue, while the SVG remains black
Here's a CodeSandbox demonstrating the problem:
My Current Tabs Component:
// #ts-nocheck
import React, { useState } from 'react';
import styled from '../../styles/styled';
type Props = {
children: React.ReactNode;
};
export const Tabs = (props: Props) => {
const { children } = props;
const [tab, setTab] = useState(0);
const childrenList = React.Children.toArray(children);
const tabs = childrenList.map((child, idx) => {
const title = (child as any).props.title ?? idx;
return (
<StyledTabs key={title} className={tab === idx ? 'activeTab' : ''} onClick={() => setTab(idx)}>
{title}
</StyledTabs>
);
});
const current = childrenList[tab];
return (
<div>
<div>{tabs}</div>
<div>{current}</div>
</div>
);
};
const StyledTabs = styled.button`
margin: 0 10px;
padding: 0 10px;
padding-bottom: 5px;
border: none;
background: transparent;
display: inline-block;
font-weight: 700;
text-transform: uppercase;
&.activeTab {
color: #1471da;
border-bottom: 1px solid #1471da;
outline: none;
padding-bottom: 5px;
}
`;
Page where Tabs Component is used :
const OverviewIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" width="35" height="35">
<path d="M0 0h16v16H0zM19 0h16v16H19zM0 19h16v16H0zM19 19h16v16H19z" />
</svg>
);
const OverviewTab = () => (
<>
<OverviewIcon />
<span>OVERVIEW</span>
</>
);
...
<Tabs>
<div title={<OverviewTab />}>
<ContentSection></ContentSection>
</div>
<div title={'ADDITIONAL CONTACTS'}>
<h1>CONTACTS</h1>
</div>
</Tabs>
To change an svg color, use fill instead within your scss :
&.activeTab {
color: #1471da;
fill: #1471da;
border-bottom: 1px solid #1471da;
outline: none;
padding-bottom: 5px;
}
Is it possible to apply a few styles of properties at once?
const Button = styled.div`
color: blue;
opacity: 0.6;
background-color: #ccc;
`
I need to pass active property, which will affect color, opacity, background-color. How can I apply styles for the active button at once instead of declaring conditions for each property?
const Button = styled.div`
color: ${props.active ? 'green' : 'blue'};
opacity: ${props.active ? 1 : 0.6};
background-color: : ${props.active ? 'white' : '#ccc'};
Create two classes and switch that classes according to property active
For example -
CSS
.activeClass{
color: green;
opacity: 1 ;
background-color:white;
}
.inactiveClass{
color: blue;
opacity: 0.6;
background-color: #ccc;
}
in Render
<button id="mybtn" className={this.props.active ? 'activeClass' : 'inactiveClass'} >mybutton</button>
See working example here
A common approach is a conditional rendering of CSS blocks with css API:
const first = css`
color: green;
opacity: 1;
background-color: white;
`;
const second = css`
color: blue;
opacity: 0.6;
background-color: #ccc;
`;
const Button = styled.div`
${({ active }) => (active ? first : second)}
`;
const App = () => {
const [active, trigger] = useReducer(p => !p, false);
return (
<Button active={active} onClick={() => trigger()}>
Press Me
</Button>
);
};
Or using common utilities like swithProp from styled-tools:
import styled, { css } from "styled-components";
import { switchProp, prop } from "styled-tools";
const Button = styled.button`
font-size: ${switchProp(prop("size", "medium"), {
small: prop("theme.sizes.sm", "12px"),
medium: prop("theme.sizes.md", "16px"),
large: prop("theme.sizes.lg", "20px")
}, prop("theme.sizes.md", "16px"))};
${switchProp("theme.kind", {
light: css`
color: LightBlue;
`,
dark: css`
color: DarkBlue;
`
}, css`color: black;`)}
`;
<Button size="large" theme={{ kind: "light" }} />
I am querying data for my react site using graphql from my CMS (prismic.io) in order to produce color themed pages. I want to pass a variable or props into my styled component to change the background color based on what is sent back from the CMS.
In the below example, my graphql query will return a HEX that has been inputted by the user, this would then be applied to buttons etc to theme that page.
The colour can and will change from page to page as the user will be selecting it within the CMS.
Any help would be appreciated. Code example below:
Props
props.data.case_study_color
Component
const ContactButton = styled.button `
background: #004655;
color: #fff;
font-size: 2rem;
padding: 10px;
`;
You could do the following.
const ContactButton = styled.button`
background: #004655;
color: ${props => props.color || '#fff'};
font-size: 2rem;
padding: 10px;
`;
See codesandbox example here.
This would be the component code:
.....component
const [color, setColor] = React.useState("#fff");
React.useEffect(() => {
fetch(URL).then(data => {
setColor(data.response);
});
}, []);
return (
<div className="App">
<ContactButton color={color}>White</ContactButton>
</div>
);
const ContactButton = styled.button `
background: ${props => props.caseStudyColor};
color: #fff;
font-size: 2rem;
padding: 10px;
`;
<ContactButton caseStudyColor={'#004655'} />
As my solution was slightly different but based on Paul's answer it might be useful for someone else.
Button Component
const ContactButton = styled.button`
background: ${props => props.themeColor || '#004655'};`
Color Component
const themeColor = props.data.case_study_color;
Button
<ContactButton themeColor={themeColor}>Get in touch</ContactButton>
I understand that styles can be conditionally rendered such as:
const HelloWorldLabel= styled("div")<{ centered?: boolean }>`
display: ${({ centered }) => (centered ? "block" : "flex")};;
margin: ${({ centered }) => (centered ? "auto 0" : "unset")};
padding: ${({ centered }) => (centered ? "0 15px" : "unset")};
`;
This does not look DRY - How can I (is it possible) render an entire block of css styles based on props?
Something like:
const HelloWorldLabel= styled("div")<{ centered?: boolean }>`
if (centered) {
display: "block" ;
margin: $"auto 0";
padding: "0 15px" ;
} else {
......
}
`;
With styled-component, or any CSS-in-JS, you can conditionally render a css block:
import styled, { css } from 'styled-components';
const light = css`
background-color: white;
color: black;
`;
const dark = css`
background-color: black;
color: white;
`;
const Box = styled.div`
${({ isDark }) => (isDark ? light : dark)}
`;
Full Example:
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import styled, { css } from 'styled-components';
const light = css`
background-color: white;
border: 2px solid black;
color: black;
`;
const dark = css`
background-color: black;
color: white;
`;
const FlexBox = styled.div`
margin: 20px;
padding: 20px;
${({ isDark }) => (isDark ? light : dark)}
`;
const App = () => {
const [isDark, setIsDark] = useState(false);
const toggle = () => setIsDark(b => !b);
return (
<FlexBox isDark={isDark}>
<div>Some Text</div>
<button onClick={toggle}>Change Block</button>
</FlexBox>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
A less verbose way that worked for me is
const SideMenu = styled.aside`
width: 200px;
${({ isHidden }) => isHidden && `
display: none;
`}
// another random prop you need here
${({ redBg }) => redBg && `
background-color: red;
`}
`;
You can use a function and return the css based on prop:
const HelloWorldLabel= styled("div")`
${({centered}) => {
if (centered) {
return `
display: "block" ;
margin: "auto 0";
padding: "0 15px";
`
} else {
return `// Other styles here`
}
}}
`;
The alternative is
let customCss = setCustomCss(position) => {
let positionCss = {
center: [ 'css: value;', 'css:value;'],
left: .....
right: ....
}
return return positionCss[position];
}
let HelloWorldLabel= styled('div')(customCss, {
/* css common to all */
})