graphql-css
is a blazing fast CSS-in-GQL™ library that converts GraphQL queries into styles for your components.
Comes with a bunch of utilities so it's easy to integrate with your favourite way of building components.
npm install graphql-css
# or
yarn add graphql-css
graphql-css
has three peer dependencies:
glamor
graphql
graphql-tag
It's likely you already have these installed, but in the case you don't you just need to run npm install <package>
or yarn add <package>
to install them.
import gqlCSS from "graphql-css";
import styles from "your-style-guide";
const textStyles = gql`
{
typography {
h2
}
marginLeft: spacing {
xl
}
color: colors {
green
}
}
`;
const Text = gqlCSS(styles)(textStyles);
const App = () => <Text>This is a styled text</Text>;
Playground: https://codesandbox.io/s/jq22wyqm3
graphql-css
exports a few different components and utility functions:
gqlCSS()
: an utility function to build glamorous components<GqlCSS>
: a component that displays the queried styles<GqlCSSProvider>
: a provider component that broadcasts the styles object to any child<GqlCSS>
componentwithGqlCSS
: a High-Order Component that injects styles in the components<WithGqlCSS>
: a function-as-a-child component that does the same thing as the HOC but it's cooler
gqlCSS
needs to be initialised with the styles from the styleguide in a JSON format (check examples folder for a detailed example).
It works with the following format gqlCSS(styles)(query, element)
:
Arg | Type | Default | Definition |
---|---|---|---|
styles | object | The styleguide object with all the rules | |
query | gql | The gql query to get the styles | |
component | string || node || boolean | "div" | HTML element or React component to be displayed. If set to false only styles are returned. |
Here's how you can use it:
const Text = gqlCSS(styles)(query);
...
<Text>This is a styled text<Text>
alternatively you can also initialise it separately and reuse it:
const getStyles = gqlCSS(styles);
...
const ComponentOne = getStyles(queryOne);
const ComponentTwo = getStyles(queryTwo);
gqlCSS
returns a glamorous
component by default, which means it accepts everything that glamorous
supports such as additional styling through the css
prop or changing the HTML element used.
const Component = gqlCSS(styles)(query);
const ComponentH1 = gqlCSS(styles)(query, "h1");
...
<Component css={{ marginTop: 10 }} />
<ComponentH1 />
If the component
argument is set to false it'll only return the styles object so it can be used with other libraries or just inline styles.
const styles = gqlCSS(styles)(query, false);
...
<div styles={styles}>Inline styled text</div>
<GqlCSS>
component allows for a more declarative API and accepts these props:
Prop | Type | Default | Definition |
---|---|---|---|
styles | object | The styleguide object with all the rules | |
query | gql | The gql query to get the styles | |
component | string || node | "div" | HTML element or React component to be displayed |
All the remaining props are passed to the generated component so you can still use glamorous
API. Here are some examples:
...
<GqlCSS styles={styles} query={query}>This is a styled text</GqlCSS>
<GqlCSS styles={styles} query={queryH1} component="h1">This is a styled H1 heading</GqlCSS>
<GqlCSS styles={styles} query={queryH1} css={{ marginBottom: 10 }}>This is a custom styled text</GqlCSS>
...
The <GqlCSSProvider>
component allows to pass down the styles definition to any <GqlCSS>
component that exists down the tree. Ideally, you'd use <GqlCSSProvider>
in the root of your application.
<GqlCSSProvider styles={styles}>
<App />
</GqlCSSProvider>
// Somewhere inside your App
<GqlCSS query={h1Styles} css={{ marginTop: 30 }}>
Using provider
</GqlCSS>
<div>
<div>
<span>
<GqlCSS query={h2Styles}>Deep nested child using provider</GqlCSS>
</span>
</div>
</div>
withGqlCSS
is a HOC that injects the styles to your existing component through the gqlStyles
prop.
// In component.js
const Component = ({ gqlStyles }) => <div styles={gqlStyles}>...</div>;
export default withGqlCSS(styles, query)(Component);
To avoid always adding the styles you can initialise the existing HOC with your styleguide and then reuse it in the code.
// in your HOC file
import styles from "your-style-guide";
import { withGqlCSS } from "graphql-css";
export const myHOC = (query) => withGqlCSS(styles, query);
// in your component file
export myHOC(query)(Component);
<WithGqlCSS>
works similarly to withGqlCSS
but uses the function-as-a-child aka render props pattern.
<WithGqlCSS styles={styles} query={h2Styles}>
{({ gqlStyles }) => <div style={gqlStyles}>Render props component</div>}
</WithGqlCSS>
The styles object is a valid JSON object that is used to define the styleguide of your project. Usually it includes definitions for colors, spacing, typography, etc.
const base = 4
const styles = {
typography: {
scale: {
s: base * 3,
base: base * 4,
m: base * 6,
l: base * 9,
xl: base * 13,
xxl: base * 20,
unit: "px"
},
weight: {
thin: 300,
normal: 400,
bold: 700,
bolder: 900,
},
},
spacing: {
s: base,
base: base * 2,
m: base * 4,
l: base * 6,
xl: base * 8,
xxl: base * 10,
},
colors: {
blue: "blue",
green: "green",
red: "red",
},
};
This is completely up to you and one of the big advantages of using graphql-css
as you can adapt it to your needs. As long as the styles and the queries match their structure, there shouldn't be much problem.
You can also specify the unit of each property by definining the unit
key.
scale: {
s: base * 3,
base: base * 4,
m: base * 6,
l: base * 9,
xl: base * 13,
xxl: base * 20,
unit: "em"
},
The GraphQL query follows the structure of the styles object with a few particular details. When building the query you need to alias the values you're getting from the style guide to the correspondent CSS property. Here's a quick example:
{
typography {
fontSize: scale {
xl
}
fontWeight: weight {
bold
}
}
}
This also means that you can reuse the same query by using different alias:
{
marginLeft: spacing {
l
}
paddingTop: spacing {
xl
}
}
Because This is just GraphQL™, you can also create fragments that can then be included in other queries:
const h1Styles = gql`
fragment H1 on Styles {
typography {
fontSize: scale {
xl
}
fontWeight: weight {
bold
}
}
}
`
const otherH1Styles = gql`
${h1Styles}
{
...H1
color: colors {
blue
}
}
`;
This is a powerful pattern that avoids lots of repetitions and allows for a bigger separation of concerns.
You can also override the pre-defined unit directly in your query by using the argument unit
:
{
marginLeft: spacing(unit: "em") {
l
}
paddingTop: spacing {
xl
}
}
This will return marginLeft: 24em, paddingTop: 32px
.
One of the big advantages of CSS-in-GQL™ is that you can use the power of variables to build custom queries. In graphql-css
that means that we can easily define variants (think themes) for specific components.
const styles = {
theme: {
light: {
button: {
// button light styles
},
},
dark: {
button: {
// button dark styles
},
},
},
};
const stateStyles = gql`
{
theme(variant: $variant) {
button
}
}
`;
// This can also be a stateful component that changes the variant according to state.
// Please check the examples folder for a detailed example.
const StyledComponent = gqlCSS(styles)(stateStyles, null, { variant: "light" });
You can use yarn run dev
and yarn run dev:server
to run the examples and test this library before using it in your project.
Please follow our contributing guidelines.