website/docs/11.7.0/guides/usage-with-react.mdx
# Usage with React
Fela was always designed with React in mind, but is **not** bound to React by default.<br />
If you want to use it with React, you should also install the official [React bindings for Fela](https://github.com/robinweser/fela/tree/master/packages/react-fela).
```bash
yarn add react-fela
```
## Passing the Renderer
In order to style components, we first need to wrap our application with the [RendererProvider](api/react-fela/RendererProvider) component.<br />
It leverages React's [context](https://reactjs.org/docs/context.html) APIs to pass our [Renderer](basics/renderer) to all child components.
```jsx name=App.js
import { createRenderer } from 'fela'
import { RendererProvider } from 'react-fela'
import MyApp from './MyApp'
const renderer = createRenderer()
export default () => (
<RendererProvider renderer={renderer}>
<MyApp />
</RendererProvider>
)
```
## Styling Components
With [hooks](https://reactjs.org/docs/hooks-intro.html) being added to React, styling your components with Fela has never been easier. <br />
react-fela ships the `useFela` hook which returns an object containing a `css` function. <br/>
Calling that function will render all passed styles and return the generated class names.
```jsx name=Button.js
import React from 'react'
import { useFela } from 'react-fela'
function Button({ children, fontSize = 16 }) {
const { css } = useFela()
return (
<button
className={css({
padding: 10,
fontSize,
color: 'darkblue',
':hover': {
color: 'blue',
},
})}>
{children}
</button>
)
}
```
### Using Rules
Instead of passing style objects directly, you might want to extract your styles into [rules](basics/rules).<br />
The `css` function also accepts rules. We can pass our props to `useFela` in order to access them inside our rules.
```jsx name=Button.js
import React from 'react'
import { useFela } from 'react-fela'
const rule = ({ fontSize }) => ({
padding: 10,
fontSize,
color: 'darkblue',
':hover': {
color: 'blue',
},
})
function Button({ children, fontSize = 16 }) {
const { css } = useFela({ fontSize })
return <button className={css(rule)}>{children}</button>
}
```
### Composition
The `css` function does not only take a single argument, but can take an array of style objects and rules.<br />
They are merged using [`combineRules`](api/fela/combineRules) thus the order of arguments matters.
```jsx name=Button.js
import React from 'react'
import { useFela } from 'react-fela'
const baseStyle = ({ fontSize }) => ({
padding: 10,
fontSize: 16,
})
const hoverStyle = {
color: 'darkblue',
':hover': {
color: 'blue',
},
}
function Button({ children, fontSize = 16, extend }) {
const { css } = useFela({ fontSize })
return (
<button className={css([baseStyle, hoverStyle, extend])}>{children}</button>
)
}
// extending the Button styles for a more specific big button
const BigButton = ({ children }) => (
<Button fontSize={20} extend={{ padding: 16 }}>
{children}
</Button>
)
```
### Fonts & Keyframes
The `useFela` hook also returns our [Renderer](basics/renderer) instance, so we can use that to render fonts, keyframes and static styles directly within our components.
> **Tip**: We can also use [fela-plugin-embedded](https://github.com/robinweser/fela/tree/master/packages/fela-plugin-embedded) to render fonts and keyframes from within our style object.
```jsx name=Button.js
import React from 'react'
import { useFela } from 'react-fela'
function Button({ children, fontSize = 16 }) {
const { css, renderer } = useFela()
// since fonts and keyframes are cached, they are only rendered once
const fontFamily = renderer.renderFont('Arial', [
'/fonts/Arial.ttf',
'/fonts/Arial.woff',
'/fonts/Arial.woff2',
])
return (
<button
className={css({
padding: 10,
fontSize,
fontFamily,
color: 'darkblue',
':hover': {
color: 'blue',
},
})}>
{children}
</button>
)
}
```
## Theming
### Passing the Theme
In order to access our theme, we need to wrap our application with the [ThemeProvider](api/react-fela/ThemeProvider) component.<br />
Similar to the `RendererProvider` it uses React's context API to pass the theme to every child component.
> **Tip**: We can also wrap specific sub-trees with different themes e.g. if only a specific part of our application should be rendered in dark mode. Multiple nested ThemeProvider instances will automatically deep-merge the theme objects unless a `overwrite` prop is passed with `false`.
```jsx name=App.js
import { createRenderer } from 'fela'
import { RendererProvider, ThemeProvider } from 'react-fela'
import MyApp from './MyApp'
import theme from './theme'
const renderer = createRenderer()
export default () => (
<RendererProvider renderer={renderer}>
<ThemeProvider theme={theme}>
<MyApp />
</ThemeProvider>
</RendererProvider>
)
```
### Using the Theme
Next to the `css` function, `useFela` also provides the current `theme` object.
> **Note**: Rules get the theme passed automatically via `props.theme`.
```jsx name=Button.js
import React from 'react'
import { useFela } from 'react-fela'
function Button({ children, fontSize = 16 }) {
const { css, theme } = useFela()
return (
<button
className={css({
padding: 10,
fontSize,
color: theme.colors.blueDark,
':hover': {
color: theme.colors.blue,
},
})}>
{children}
</button>
)
}
```
## Pre-hooks APIs
Prior to hooks, Fela shipped a couple of Higher-order and Render-props components to style React components.<br />
While we recommend using the `useFela` hook whenever possible, they are still valid APIs and can be used interchangable.
- [FelaComponent](api/react-fela/FelaComponent)
- [FelaTheme](api/react-fela/FelaTheme)
- [FelaRenderer](api/react-fela/FelaRenderer)
- [createComponent](api/react-fela/createComponent)
- [createComponentWithProxy](api/react-fela/createComponentWithProxy)
- [connect](api/react-fela/connect)
- [withTheme](api/react-fela/withTheme)
## Tips & Tricks
### Presentational Components
While not required, we highly recommend to split your components into [presentational and container components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.67qfcbme5).
Where container components manage the application logic, presentational components should only describe how your application is displayed (markup & styling). They get data passed as `props` and return a representation of your view for those props.
If we strictly separate our components, we actually only use Fela for presentational components.
---
## Related
- [react-fela](https://github.com/robinweser/fela/tree/master/packages/react-fela)
- [API Reference - `useFela`](api/react-fela/useFela)
- [API Reference - `RendererProvider`](api/react-fela/RendererProvider)
- [API Reference - `ThemeProvider`](api/react-fela/ThemeProvider)