Styling react with styled components

Freitag, 24. März 2017, #ReactStuttgart

Oliver Schmidt - @webkreation

work

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

private

married, 3 kids

wintersport, MTB

travel

food, wine

VR

in this talk

Styling React in the "past"

  CSS in JS, Inline Styles,

  CSS Modules, JSS

not in this talk

Styling React Native

Linting

Testing

Styled Components

  CSS to Styled Components

  Tagged Template Literals

  Composing, overriding, theming

  Helpers

  v2

 

 

HTML // CSS // Javascript

BEM

past

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???

React 2014

Inline Styles

<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

Inline Styles

 

 

✅ 

 

 

Inline Styles + Radium

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

Inline Styles Radium

React components

JSX(HTML)

logic

state

React 2016

CSS

build

CSS-in-JS

more Infos: React: CSS in JS by vjeux

CSS-in-JS

// 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>

CSS-in-JS

✅ 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

CSS Modules

/* 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>

CSS Modules

all of CSS

global CSS

✅ write CSS

 no build requirements

 isolated

❌ colocated

❌ Theming

JSS

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>;
  }
}

JSS

✅ supports all of CSS

✅ supports global CSS

 write CSS

 no build requirements

 isolated

 colocated

 (Theming)

CSS vs. JS/React

Styled Components

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 start

CSS to Styled Components

Project 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'

Tagged Template Literals

Multi line strings

${Interpolations}

many Interpolations

styled components

Adapting based on props

Full CSS Support

Overriding Component Styles

Styling third-party components

Theming

Passed Props

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;

Adapting based on props

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;

Full CSS Support

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>
    );
}

Overriding Component Styles

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;

Styling third-party components

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;

Theming

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;
`

Theming

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;

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

use existing css packages

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>

Styled Componets-App inside Angular App

=> completely isolated styles via styled-components

Syntax highlight

auto-complete

lint support

 

for Atom, Visual Code and Sublime Text.

IDE support

v2.0  main differences

v2.0 closed issues

v2.0 open issues

more infos

Oliver Schmidt

Oberer Bohl 16

78601 Mahlstetten

 

E-mail: kontakt@webkreation.de

Skype: webkreation

Twitter: @webkreation

XING: https://www.xing.com/profile/Oliver_Schmidt59

about me

Styling react with styled components

By webkreation

Styling react with styled components

  • 639