@patternfly/react-styles
Library that provides CSS-in-JS capabilites along with build plugins to convert raw css imports to a consumable form for JS. This approach is very similar to how css-modules works.
Getting Started
This library has 3 main parts.
- A babel plugin to transform css imports into a JS import
- A
StyleSheet
helper that parses raw css and returns a JS object to reference classnames. - A
css
helper function to combine string CSS classes and any returned from theStyleSheet
. It also takes care of doing the CSS injection.
Detailed design
@patternfly/react-styles/babel
Babel plugin The babel plugin will take care of transforming and .css
imports to javascript files that use the StyleSheet API listed below.
Example
.babelrc
{
plugins: [
[
'@patternfly/react-styles/babel',
{
srcDir: './src',
outDir: './dist/esm',
useModules: true
}
]
]
}
In
@patternfly/patternfly/components/Button/styles.css
.button {
background-color: #000;
}
src/components/Button.js
import React from 'react';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/patternfly/components/Button/styles.css';
import overrides from './Button.overrides.css';
const Button = ({ children, variant }) => <button className={css(styles.button)}>{children}</button>;
Out
dist/styles/components/Button.overrides.js
import { StyleSheet } from '@patternfly/react-styles';
export default StyleSheet.parse('.bg{background-color:#000}');
dist/styles/node/@patternfly/patternfly/components/Button/index.js
import { StyleSheet } from '@patternfly/react-styles';
const styles = StyleSheet.parse('.button{color: black;}');
dist/components/Button.js
import React from 'react';
import { css } from '@patternfly/react-styles';
import overrides from '../../styles/components/Button/Button.overrides.js';
import styles from '../../styles/node/@patternfly/patternfly/components/Button/index.js';
const Button = ({ children }) => <button className={css(styles.button)}>{children}</button>;
StyleSheet.parse(cssString): { [key: string]: PFStyleObject }
Parses a string of CSS and extracts classes out so that they can be referenced from an object instead of as a string value. CSS is injected through the css
utility. The keys provided are a mapping to a camel-cased version of the className with pf-(l|c|p)-
removed.
pf-c-button --> button
pf-is-primary --> isPrimary
pf-l-grid --> grid\
Any modifiers are placed under a nested property modifiers
:
pf-m-active --> modifiers.active pf-m-block --> modifiers.block
Example
import { StyleSheet, css } from '@patternfly/react-styles';
const styles = StyleSheet.parse(`
.pf-c-button { background: green }
.pf-m-active { background: red }
`);
const btn = document.createElement('button');
btn.classList.add(css(styles.button, styles.modifiers.active));
// <button class="pf-c-button pf-is-active" />
// If you just need to inject all of the styles manually you can do this by calling the inject method on the styles object.
// Note: using css() does this in a more efficient manner and this should be only be used as an escape hatch.
styles.inject();
StyleSheet.create({ [key: string]: object | string | Array<object> }): { [key: string]: string }
StyleSheet.create takes an object with each property calling css
from emotion. This is largely provided for backwards compatibility, and will likely be removed in the future.
Example
import { StyleSheet } from '@patternfly/react-styles';
const styles = StyleSheet.create({
first: { backgroundColor: 'red' },
second: `background-color: red`,
third: [{ color: 'red' }, { backgroundColor: 'green' }]
});
For more info on how each property is handled see emotion css docs.
css(...styles: Array<PFStyleObject | string | void>): string
Joins classes together into a single space-delimited string. If a PFStyleObject
or a result from StyleSheet.create
is passed it will inject the CSS related to that object. This is similar to the classnames package.
Example
import { css } from '@patternfly/react-styles';
import styles from './Button.css';
const Buttton = ({ isActive, isDisabled, children }) => (
<button
disabled={isDisabled}
className={css(styles.button, isActive && styles.isActive, isDisabled && styles.isDisabled)}
>
{children}
</button>
);
DOM output
<button disabled="" class="pf-c-button pf-is-disabled">
Hello World
</button>
getModifier(styles: { [key: string]: PFStyleObject }, modifier: string, defaultModifer?: string): PFStyleObject | null;
Since PatternFly 4 Core is maintaining a pattern of using pf-m-modifier
for modifiers we will provide a utility for consumers to easily get the modifier given the style object and the desired modifier. A default can be provided as well if the given variant does not exist. Returns null
if none are found.
Example
const styles = StyleSheet.parse(`
.button {}
.pf-m-secondary {}
.pf-m-primary {}
`);
const Button = ({
variant // primary | secondary,
children,
}) => (
<button
className={css(
styles.button,
getModifier(styles, variant, 'primary'),
)}
>
{children}
</button>
);
Server Rendering
Since the css is referenced from JS server rendering is supported. For an example of this see: gatsby-ssr.js
Snapshot Testing
This package exports a snapshot serializer to produce more useful snapshots. Below is an example
Before
exports[`primary button 1`] = `
<button
className="pf-c-button pf-m-primary"
disabled={false}
type="button"
/>
`;
After
exports[`primary button 1`] = `
.pf-c-button.pf-m-primary {
display: inline-block;
padding: 0.25rem 1.5rem 0.25rem 1.5rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
text-align: center;
white-space: nowrap;
background-color: #00659c;
border: 0px;
border-radius: 30em;
box-shadow: inset 0 0 0 2px #00659c;
color: #ffffff;
}
<button
className="pf-c-button pf-m-primary"
disabled={false}
type="button"
/>
`;
Now if the background-color is changed the snapshot will fail, and your will see an output similar to below.
- Snapshot
+ Received
.pf-c-button.pf-m-primary {
display: inline-block;
padding: 0.25rem 1.5rem 0.25rem 1.5rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
text-align: center;
white-space: nowrap;
- background-color: #00659c;
+ background-color: green;
border: 0px;
border-radius: 30em;
box-shadow: inset 0 0 0 2px #00659c;
color: #ffffff;
}
<button
className="pf-c-button pf-m-primary"
disabled={false}
type="button"
/>
This is similar to the utilities jest-aphrodite-react, jest-styled-components, and jest-glamor-react