Styled Components

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

npm i styled-components

Usaremos el siguiente plugin de visual studio code: vscode-styled-components from Julien Poissonnier

Cuando usamos JSX sin styled-components, los atributos son pasados al DOM obligatoriamente como texto.

En el Visual Studio Code, utilizaría la siguiente extensión para tener autocompletado y coloreado de sintaxis:

vscode-styled-components

Etiquetas anidadas

import { Box } from './styled';
const App = () => <Box><div></div></Box>;
export default App;
import styled from 'styled-components';

export const Box = styled.div`
    background-color: salmon;
    padding: 30px;

    div{
        background-color: palegreen;
        width: 100px;
        height: 100px;
    }
`;

Usando props

Para personalizar el comportamiento de los styled componentes, usaremos siempre props con valores booleanos, con el propósito de no complicar la lógica que va dentro de la definición del styled component.

Estilos en función de props

<Component isRight={true}/>
export const Component = styled.div`
  background-color: ${({ isRight}) => isRight ? 'green' : 'red'};
`;

Atributos en función de props

<Input myMaxLength={2}/>
export const Box = styled.div.attrs({ className: 'pt-3' })``;
export const Input = styled.input.attrs(props => ({
    type: "password",
    maxLength: props.myMaxLength || 5,
    }))`
  color: blue;
`;

Error al usar props

Al usar props que utilicen camelCase obtendremos un mensaje de error similar a este:

React does not recognize the `isVisible` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `isvisible` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

Podemos evitar este mensaje de error poniendo el símbolo de dolar antes del nombre de la prop. De esta forma, evitamos que la prop se propague al DOM.

<MyStyledComponent $isVisible={true} />

Ejercicio

1. Crear un styled-component (no un componente funcional de React, bastará con un styled-component )y cuando pulsemos sobre un botón, que cambie de color. Para ello, usaremos un código similar a este:

App.js

<button onClick={ () => setColor('red')}>Cambiar color</button>
<MyStyledComponent color={color}/>

Por tanto, tendremos que modificar el código de dos ficheros: App.js y styles.js (que contendrá el styled-component).

2. Crear un componente que usará styled-components y que mostrará un popup cuando reciba una prop visible con el valor true.

Crearemos un componente llamado Popup que recibirá como props visible y setVisible.

const Popup = ({visible}) => <Back visible={visible} />;
export default Popup;

En dicho componente, utilizaremos styled componentes para que el componente Back sea visible en función de si su propiedad visible es true o false.

Llamando al método setVisible dentro del componente PopUp, nos comunicaremos con el componente App para ocultar el componente.

<button onClick={ () => setVisible(!visible)}>Mostrar popup</button>
<Popup visible={visible}/>

Hacer hover

export const Panel = styled.div`
  background-color: salmon;
  &:hover {
	  background-color: paleGreen
  }
`;

Heredar de otro componente

export const Rectangulo = styled(Cuadrado)`
  width: 200px;
`;

Incrustar código

// El código de BigText debe estar definido antes de ser usado

import styled, { css } from 'styled-components';

const BigText = css`
	font-size: 3rem;
`;

export const RedText = styled.p`
	background: red;
	${BigText};
`;

export const BlueText = styled.p`
	background: blue;
	${BigText}
`;

Añadir animaciones

import styled, { keyframes } from 'styled-components';

const showIt = keyframes`
    to{ opacity: 1}
`;

export const TextPanel = styled.div`
    animation: 5s ${showIt} forwards;
`;

Animaciones con parámetro

En este caso, trataremos la animación como una función:

const statusBarAnimation = (level) => keyframes`
    to{   width: ${level+ '%'}; }
`;

export const StatusBarContainer = styled.div`
        width:0;
        animation: ${({ level }) => statusBarAnimation(level)} 1s forwards;
`;

Para hacer media queries

const desktopStartWidth = 996;

const desktop = `@media (min-width: ${desktopStartWidth}px)`;
const mobile = `@media (max-width: ${desktopStartWidth}px)`;

const Cuadrado = styled.div`
	...
	${mobile} {
		width:100%;
	}
`;

Para maquetar el body

import styled, { createGlobalStyle } from 'styled-components';

export const GlobalStyle = createGlobalStyle`
	body {
		background-color: salmon;
	}
`;
./src/App.js
import { GlobalStyle } from './styles';

const App = () => (
    <div>
      <GlobalStyle />
      <p>App content</p> 
    </div>
);

export default App;

Cargar una tipografía:

Lo haremos usando GlobalStyle:

export const GlobalStyle = createGlobalStyle`
	@font-face {
        font-family: myFont;
        src: url(${font});
    }
`;

Uso de themes

import { ThemeProvider } from "styled-components";

const monteserinTheme = {
    primaryColor: 'red'
}

const otroTheme = {
    primaryColor: 'blue'
}

const theme = import.meta.env.VITE_STYLES_PROFILE
    === 'monteserin' ? monteserinTheme : jordiTheme;

const Theme = ({ children }) => {

    return (
        <ThemeProvider theme={theme}>
            {children}
        </ThemeProvider>
    )
}

export default Theme;
const App = () => {
    return (
        <Theme >
           ...
        </Theme >
    )
}

export default App

Como estructurar un componente que utiliza styled-components

Styled Components 1
./src/App.js
import Box from './components/box';
const App = () => <Box/>;
export default App;
./src/components/Box/index.js
import Box from './Box';
export default Box;
./src/components/Box/Box.jsx
import { Btn } from './Box.styled';
const MyBtn = () => <Btn onClick="alert('hola)">hola</Btn>;
export default MyBtn;
./src/components/Box/Box.styles.js
import styled from 'styled-components';

export const Btn = styled.button`
    width: 70px;
    height: 70px;
    background-color: pink;
    color: pink;
`;