tools for external stylesheets:
CSS-in-JS libraries:
utility: npm package classnames:
import classNames from 'classnames';
<div
className={classNames({
todoitem: true,
completed: props.completed,
})}
>
[...]
</div>;
CSS modules are preconfigured in create-react-app; they enable using CSS class names that are guaranteed to be unique across CSS files
import styles from './TodoItem.module.css';
<div className={styles.todoItem + ' ' + styles.completed}>
...
</div>;
possible output in the HTML:
<div
class="TodoItem_todoItem__L9V1E TodoItem_completed__9bPW1"
>
...
</div>
<div className={classNames({
[styles.todoitem]: true,
[styles.completed]: props.completed
})}>
CSS-in-JS: JavaScript is used to generate and attach stylesheets
Nowadays it's considered ok to put styling in the same file as JavaScript / HTML
libraries:
basic example in emotion:
import { css } from '@emotion/css';
<button
className={css({
color: 'blue',
'@media (min-width: 600px)': { color: 'green' },
'&:hover': { color: 'red' },
})}
>
foo
</button>;
alternative notation: via "tagged template strings"
<button
className={css`
color: blue;
&:hover {
color: red;
}
`}
>
foo
</button>
recommended: use the css
property instead of className
(requires an extra source transform)
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
<button css={css({ color: 'blue' })}>foo</button>;
styled components: approach where components are created whose only task is adding styling to HTML elements
example: PrimaryButton
= a button
element with extra styling
creating a styled component with emotion:
import styled from '@emotion/styled';
const PrimaryButton = styled.button({
color: 'blue',
'&:hover': { color: 'red' },
});
theoretical manual version:
function PrimaryButton(props) {
return (
<button
{...props}
className={css({
color: 'blue',
'&:hover': { color: 'red' },
})}
/>
);
}
dynamic styles via props:
with JavaScript:
const Button = styled.button({
padding: 8,
color: (props) => (props.primary ? 'blue' : 'black'),
});
with TypeScript:
const Button = styled.button<{ primary: boolean }>({
padding: 8,
color: (props) => (props.primary ? 'blue' : 'black'),
});
exercise: use some styling tools to add extra styling to an existing application (e.g. to the slideshow)
animating appearance / disappearance of elements:
advanced libraries:
basic animations: via CSS transitions
.TodoItem {
background-color: salmon;
transition-property: background-color;
transition-duration: 0.5s;
}
.TodoItem--Completed {
background-color: lightgrey;
}
phases for appearance / disappearance of elements:
react-transition-group: based on CSS class names
example with framer motion:
<AnimatePresence>
{hovered ? (
<motion.button
animate={{ opacity: 1 }}
initial={{ opacity: 0 }}
exit={{ opacity: 0 }}
onClick={() => props.onDelete(props.todo.id)}
>
delete
</motion.button>
) : null}
</AnimatePresence>
example with framer motion:
<AnimatePresence>
{todos.map((todo) => (
<motion.li
key={todo.id}
animate={visibleStyle}
initial={hiddenStyle}
exit={hiddenStyle}
>
{todo.title}
</motion.li>
))}
</AnimatePresence>
example with react-spring:
<Transition
items={hovered}
from={{ opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}
reverse={hovered}
>
{(style, hovered) =>
hovered ? (
<animated.button
style={style}
onClick={() => props.onDelete(props.todo.id)}
>
delete
</animated.button>
) : null
}
</Transition>