Web+Freelancer since 1999
FE architect and developer
React since 2014
Offline/Mobile Webapps
Travel Tech
E-Learning
L'TUR, TUI, SWISS, HLX, Thieme, Greenpeace, fr.de
married, 3 kids
wintersport, MTB
travel
food, wine
VR
Styling React in the "past"
CSS in JS, Inline Styles,
CSS Modules, JSS
Styling React Native
Linting
Testing
Styled Components
CSS to Styled Components
Tagged Template Literals
Composing, overriding, theming
Helpers
v2
HTML // CSS // Javascript
BEM
SUIT
inuitCSS
CSS is designed primarily to enable the separation of document content from document presentation, including aspects such as the layout, colors, and fonts.
WWWC December 2010
React components
JSX(HTML)
logic
state
inline styles
WTF???
<button style="
background-color: rgb(0, 216, 255);
color: white;
border: none;
border-radius: 0.25em;
font-size: 2em;
padding: 0.5em 1em;"
>
Styled Button
</button>// button,js
const styles = {
backgroundColor: "#00D8FF",
color: "white",
border: "none",
borderRadius: "0.25em",
fontSize: "2em",
padding: "0.5em 1em"
// hover???
};return (
<div>
<button style={styles}>
Styled Button
</button>
</div>
)all of CSS
global CSS
write CSS
no build requirements
isolated
colocated
Theming
❌
❌
❌
✅
✅
✅
❌
import Radium from 'radium';
const styles = {
backgroundColor: "#00D8FF",
color: "white",
border: "none",
borderRadius: "0.25em",
fontSize: "2em",
padding: "0.5em 1em"
':hover': {
background-color: white;
color: #00D8FF;
}
};const Button = () => {
return (
<div>
<button style={styles}>
Styled Button
</button>
</div>
)
}
export default Radium(Button)✅ all of CSS
✅ global CSS
❌ write CSS
✅ no build requirements
✅ isolated
✅ colocated
✅ Theming
React components
JSX(HTML)
logic
state
CSS
build
CSS-in-JS
more Infos: React: CSS in JS by vjeux
// btn.css
.btn {
background-color: #00D8FF;
color: white;
border: none;
border-radius: 0.25em;
font-size: 2em;
padding: 0.5em 1em;
}
.btn:hover {
background-color: white;
color: #00D8FF;
}
.btn--ctaction {
background-color: green;
color: white;
}import classNames from 'classnames';
const btnClass = classNames({
'btn': true,
'btn--ctaction': this.state.buyit,
});
return (
<div>
<button className={btnClass}>
Styled Button
</button>
</div>
)<button class="btn btn--ctaction">
Buy it
</button>✅ all of CSS
✅ global CSS
✅ write CSS
✅ no build requirements
❌ isolated
❌ colocated
✅ (Theming)
If you’re writing React, you have access to a more powerful styling construct than CSS class names.
You have components.
@chantastic June 2016 *
* https://medium.learnreact.com/scale-fud-and-style-components-c0ce87ec9772
/* Btn.css */
.base {
background-color: #00D8FF;
color: white;
border: none;
border-radius: 0.25em;
font-size: 2em;
padding: 0.5em 1em;
}
.base:hover {
background-color: white;
color: #00D8FF;
}
.ctaction {
composes: base;
background-color: green;
color: white;
}/* Button.js */
import styles from './styles'
return {
<button
className={
cta ? styles.ctaction : styles.base
}/>
}styles: {
base: "Btn__base__abc23423",
ctaction: "Btn__ctaction__dfe6546"
}<button class="Button__ctaction__dfe6546">
CTA Button
</button>✅ all of CSS
✅ global CSS
✅ write CSS
❌ no build requirements
✅ isolated
❌ colocated
❌ Theming
import classnames from 'classnames';
import useSheet from 'react-jss';
const styles = {
button: { padding: '1em' },
'media (max-width: 200px)': {
button: {
width: '100%'
}
}
};
@useSheet(styles)
export default class ConfirmButton extends React.Component {
render() {
const {classes} = this.props.sheet;
return
<button className={classnames(classes.button, classes.primary)}>
Confirm
</button>;
}
}✅ supports all of CSS
✅ supports global CSS
❌ write CSS
✅ no build requirements
✅ isolated
✅ colocated
❌ (Theming)
supports all of CSS
supports global CSS
write CSS
no build requirements
isolated
colocated
Theming
✅
✅
✅
✅
✅
✅
✅
const AppWrapper = styled.div`
display: flex;
flex-direction: column;
`;$ npm install -g create-react-app
$ create-react-app styled-components-demo
$ cd styled-components-demo
$ yarn add styled-components
$ yarn startProject setup in 1 minute
create-react-apps
styled-components
console.log`hello
React
Stuttgart`
['hello↵React↵Stuttgart']const name = 'ReactStuttgart'
console.log`hello ${name} members`
['hello ', 'members'] 'ReactStuttgart'const food = veryHungry ? 'Pizza' : 'Soup'
const drink = 'Beer'
console.log`I like ${foot} and ${drink}.`
['I like ', 'and', '.'] 'Pizza' 'Beer'
Multi line strings
${Interpolations}
many Interpolations
Adapting based on props
Full CSS Support
Overriding Component Styles
Styling third-party components
Theming
Demos:
https://github.com/webkreation/styling-react-with-styled-components/tree/03-styled-components-demos
$ yarn
$ yarn start
import React, { Component } from 'react';
import styled from 'styled-components';
import H2 from '../components/H2'
import Next from '../components/Next'
const Input = styled.input`
font-size: 1.25em;
padding: 0.5em;
color: palevioletred;
background: gray;
border: none;
border-radius: 3px;
`;
class PassedProps extends Component {
render() {
return (
<div>
<H2>Passed Props</H2>
<p>Styled components pass on all their props.</p>
<p>
<Input
placeholder="Type in Text" size="20" type="text" />
</p>
</div>
);
}
}
export default PassedProps;
import React from 'react'
import styled from 'styled-components'
import H2 from '../components/H2'
const Button = styled.button`
display: block;
background: ${props => props.action ? 'green' : '#00D8FF'};
color: ${props => props.action ? 'white' : 'black'};
border: none;
border-radius: 0.25em;
font-size: ${props => props.bigger ? '2em' : '1em'};
padding: 0.5em 1em;
margin: 1em 0;
`;
const PassedProps = () => {
return (
<div>
<H2>Adapting based on props</H2>
<p>
<Button>Normal</Button>
<Button action>Buy now</Button>
<Button action bigger>Buy now bigger</Button>
</p>
</div>
);
}
export default PassedProps;const Button = styled.button`
display: block;
background: ${props => props.action ? 'green' : '#00D8FF'};
color: ${props => props.action ? 'white' : 'black'};
color: white;
border-radius: 0.25em;
font-size: ${props => props.bigger ? '2em' : '1em'};
padding: 0.5em 1em;
margin: 1em 0;
cursor: pointer;
&:hover {
background-color: #FFCE38;
}
@media (min-width: 1024px) {
padding: 1em 3em;
}
`;
const PassedProps = () => {
return (
<div>
<H2>Full CSS Support</H2>
<p>
<Button bigger>:hover and @media</Button>
</p>
<Next nextPage="/04"/>
</div>
);
}import React, { Component } from 'react'
import styled from 'styled-components'
import H2 from '../components/H2'
import Next from '../components/Next'
import Button from '../components/Button'
const UppercaseButton = styled(Button)`
text-transform: uppercase;
border: 10px solid green;
`
const Overriding = () => {
return (
<div>
<H2>Overriding Component Styles</H2>
<p>
<Button>Button</Button>
<UppercaseButton>Button Uppercase Border</UppercaseButton>
</p>
<Next nextPage="/05"/>
</div>
);
}
export default Overriding;
import React from 'react'
import styled from 'styled-components'
import H2 from '../components/H2'
import { Link } from 'react-router-dom'
const StyledLink = styled(Link)`
display: block;
background-color: red;
color: white;
padding: 10px;
text-align: center;
margin: 1em 0;
text-decoration: none;
`;
const ThirdPartyComponents = () => {
return (
<div>
<H2>Styling third-party components</H2>
<p>
<Link to="/">Standard, unstyled Link from React-Router</Link>
</p>
<p>
<StyledLink to="/02">Style React-Router Link</StyledLink>
</p>
</div>
);
}
export default ThirdPartyComponents;
import React from 'react'
import styled, {ThemeProvider} from
'styled-components'
import H2 from '../components/H2'
const theme = {
theme1: {
mainColor: 'gold',
background: 'gray'
},
theme2: {
mainColor: 'red',
background: 'black'
}
}
const Button = styled.button`
display: block;
background: ${props => props.theme.background};
color: ${props => props.theme.mainColor};
border: none;
border-radius: 0.25em;
font-size: 2em;
padding: 0.5em 1em;
margin: 1em 0;
cursor: pointer;
`const Circle = styled.div`
display: inline-block;
background: ${props => props.theme.mainColor};
border-radius: 50%;
width: 20px;
height: 20px;
margin-right: 10px;
`
const Theming = () => {
return (
<div>
<H2>Theming</H2>
<ThemeProvider theme={theme.theme1}>
<Button>
<Circle/>
Button
</Button>
</ThemeProvider>
<ThemeProvider theme={theme.theme2}>
<Button className="test">
<Circle/>
Button
</Button>
</ThemeProvider>
</div>
);
}
export default Theming;
class Theming extends Component {
constructor(props) {
super(props);
this.state = {
theme: "theme1"
};
this.handleThemeClick = this.handleThemeClick.bind(this);
}
handleThemeClick() {
this.setState({theme: "theme2"});
}
render() {
const { state } = this.props;
return (
<div>
<H2>Theming</H2>
<ThemeProvider theme={theme[this.state.theme]}>
<div>
<Button><Circle />Button</Button>
<Button onClick={this.handleThemeClick}>
Toggle Theme
</Button>
</div>
</ThemeProvider>
</div>
);
}
}
export default Theming;onClick
change theme
const IconStyled = styled.i`
width: ${props => props.size + 'px'};
....
color: ${props => props.currentDay ? 'white' : colors.thieme.blue};
`;<DonutStyled size={size} title={percentage + '%'}>
<IconStyled
size={size}
currentDay={currentDay}
className={dayDone ? 'mdi mdi-check' : null}/>
<svg width={size} height={size} viewBox={viewBox}>...</svg>
</DonutStyled><link
href="...materialdesignicons.min.css"
rel="stylesheet"
><div size="36" title="12%" class="bpKDSq">
<i size="36" class="mdi mdi-check haomqU"></i>
<svg/>
</div>=> completely isolated styles via styled-components
Syntax highlight
auto-complete
lint support
for Atom, Visual Code and Sublime Text.
Oliver Schmidt
Oberer Bohl 16
78601 Mahlstetten
E-mail: kontakt@webkreation.de
Skype: webkreation
Twitter: @webkreation
XING: https://www.xing.com/profile/Oliver_Schmidt59