# Griffel for React.js A package with wrappers and APIs to be used with React.js. - [Install](#install) - [`makeStyles()`](#makestyles) - [Pseudo & class selectors, at-rules, global styles](#pseudo--class-selectors-at-rules-global-styles) - [Keyframes (animations)](#keyframes-animations) - [CSS Fallback Properties](#css-fallback-properties) - [RTL support](#rtl-support) - [`mergeClasses()`](#mergeclasses) - [`makeStaticStyles()`](#makestaticstyles) - [`makeResetStyles()`](#makeresetstyles) - [`createDOMRenderer()`, `RendererProvider`](#createdomrenderer-rendererprovider) - [compareMediaQueries](#comparemediaqueries) - [insertionPoint](#insertionpoint) - [styleElementAttributes](#styleelementattributes) - [`TextDirectionProvider`](#textdirectionprovider) - [Shorthands](#shorthands) - [`shorthands.borderColor`](#shorthandsbordercolor) - [`shorthands.borderStyle`](#shorthandsborderstyle) - [`shorthands.borderWidth`](#shorthandsborderwidth) ## Install ```bash npm install @griffel/react # or yarn add @griffel/react ``` ## `makeStyles()` Is used to define styles, returns a React hook that should be called inside a component: ```tsx import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ button: { color: 'red' }, icon: { paddingLeft: '5px' }, }); function Component() { const classes = useClasses(); return (
); } ``` ### Pseudo & class selectors, at-rules, global styles `makeStyles()` supports pseudo, class selectors and at-rules. ```ts import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ root: { ':active': { color: 'pink' }, ':hover': { color: 'blue' }, // :link, :focus, etc. '.foo': { color: 'black' }, ':nth-child(2n)': { backgroundColor: '#fafafa' }, '@media screen and (max-width: 992px)': { color: 'orange' }, '@container (max-width: 992px)': { color: 'orange' }, '@container foo (max-width: 992px)': { color: 'orange' }, '@supports (display: grid)': { color: 'red' }, '@layer utility': { marginBottom: '1em' }, }, }); ``` Another useful feature is `:global()` selector, it allows connecting local styles with global selectors. ```ts import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ root: { ':global(html[data-whatintent="mouse"])': { backgroundColor: 'yellow' }, // outputs: html[data-whatintent="mouse"] .abcd { background-color: yellow } }, }); ``` ### Keyframes (animations) `keyframes` are supported via `animationName` property that can be defined as an object or an array of objects: ```tsx import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ root: { animationIterationCount: 'infinite', animationDuration: '3s', animationName: { from: { transform: 'rotate(0deg)' }, to: { transform: 'rotate(360deg)' }, }, }, array: { animationIterationCount: 'infinite', animationDuration: '3s', animationName: [ { from: { transform: 'rotate(0deg)' }, to: { transform: 'rotate(360deg)' }, }, { from: { height: '100px' }, to: { height: '200px' }, }, ], }, }); ``` ### CSS Fallback Properties Any CSS property accepts an array of values which are all added to the styles. Every browser will use the latest valid value (which might be a different one in different browsers, based on supported CSS in that browser): ```js import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ root: { overflowY: ['scroll', 'overlay'], }, }); ``` ### RTL support Griffel uses [rtl-css-js](https://github.com/kentcdodds/rtl-css-js) to perform automatic flipping of properties and values in Right-To-Left (RTL) text direction defined by `TextDirectionProvider`. ```js import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ root: { paddingLeft: '10px', }, }); ``` ⬇️⬇️⬇️ ```css /* Will be applied in LTR */ .frdkuqy { padding-left: 10px; } /* Will be applied in RTL */ .f81rol6 { padding-right: 10px; } ``` You can also control which rules you don't want to flip by adding a `/* @noflip */` CSS comment to your rule: ```js import { makeStyles } from '@griffel/react'; const useClasses = makeStyles({ root: { paddingLeft: '10px /* @noflip */', }, }); ``` ⬇️⬇️⬇️ ```css /* Will be applied in LTR & RTL */ .f6x5cb6 { padding-left: 10px; } ``` ## `mergeClasses()` > 💡 **It is not possible to simply concatenate classes returned by `useClasses()`.** There are cases where you need to merge classes from multiple `useClasses` calls. To properly merge the classes, you need to use `mergeClasses()` function, which performs merge and deduplication of atomic classes generated by `makeStyles()`. ```tsx import { mergeClasses, makeStyles } from '@griffel/react'; const useClasses = makeStyles({ blueBold: { color: 'blue', fontWeight: 'bold', }, red: { color: 'red', }, }); function Component() { const classes = useClasses(); const firstClassName = mergeClasses(classes.blueBold, classes.red); // { color: 'red', fontWeight: 'bold' } const secondClassName = mergeClasses(classes.red, classes.blueBold); // { color: 'blue', fontWeight: 'bold' } return ( <>
); } ``` ## `makeStaticStyles()` Creates styles attached to a global selector. Styles can be defined via objects: ```tsx import { makeStaticStyles } from '@griffel/react'; const useStaticStyles = makeStaticStyles({ '@font-face': { fontFamily: 'Open Sans', src: `url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"), url("/fonts/OpenSans-Regular-webfont.woff") format("woff")`, }, body: { background: 'red', }, /** * ⚠️ nested and pseudo selectors are not supported for this scenario via nesting * * Not supported: * .some { * .class { ... }, * ':hover': { ... } * } * * Supported: * '.some.class': { ... } * '.some.class:hover': { ... } */ }); function App() { useStaticStyles(); return
; } ``` Or with string & arrays of strings/objects: ```tsx import { makeStaticStyles } from '@griffel/react'; const useStaticStyles1 = makeStaticStyles('body { background: red; } .foo { color: green; }'); const useStaticStyles2 = makeStaticStyles([ { '@font-face': { fontFamily: 'My Font', src: `url(my_font.woff)`, }, }, 'html { line-height: 20px; }', ]); function App() { useStaticStyles1(); useStaticStyles2(); return
; } ``` ## `makeResetStyles()` Atomic CSS has [tradeoffs](https://griffel.js.org/react/guides/atomic-css#trade-offs). Once an element has many HTML class names each pointing to different CSS rules, browser layout times slow down. There are cases when it's reasonable to flatten multiple declarations into monolithic CSS. For example, base styles for components in a UI library. Rules generated by `makeResetStyles()` are inserted into the CSS style sheet before all the Atomic CSS, so styles from `makeStyles()` will always override these rules. `makeResetStyles` returns a React hook that should be called inside a component: ```jsx import { makeStyles, makeResetStyles } from '@griffel/react'; import { mergeClasses } from './mergeClasses'; const useBaseClass = makeResetStyles({ color: 'red', padding: 0, // etc. }); const useClasses = makeStyles({ primary: { color: 'blue' }, circular: { padding: '5px', borderRadius: '5px', }, }); function Component(props) { const baseClass = useBaseClass(); const classes = useClasses(); return (