SkillAgentSearch skills...

Zacs

Zero Abstraction Cost Styling ⚡️👨‍🎨 (for React DOM & React Native)

Install / Use

/learn @Nozbe/Zacs
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<p align="center"> <img src="https://github.com/Nozbe/zacs/raw/master/assets/logo.png" alt="ZACS: Zero Abstraction Cost Styling" width="472" /> </p> <h4 align="center"> 👨‍🎨 Component styling with no performance penalty for React and React Native ⚡️ </h4> <p align="center"> <a href="https://opensource.org/licenses/MIT"> <img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License"> </a> <!-- <a href="https://travis-ci.com/Nozbe/WatermelonDB"> <img src="https://api.travis-ci.com/Nozbe/WatermelonDB.svg?branch=master" alt="CI Status"> </a>--> <a href="https://www.npmjs.com/package/@nozbe/zacs"> <img src="https://img.shields.io/npm/v/@nozbe/zacs.svg" alt="npm"> </a> </p>

What is zacs?

| <a href="https://youtube.com/watch?v=ryMvNklnDjU"><img src="https://github.com/Nozbe/ZACS/raw/master/assets/youtube-thumbnail.jpg" alt="React Native EU: A Successful Web & React Native Sharing Strategy" width="400" /></a> | | ---- | | <p align="center"><a href="https://youtube.com/watch?v=ryMvNklnDjU">📺 <strong>A Successful Web & React Native Sharing Strategy</strong></p> |

ZACS turns React components that look like this:

import zacs from '@nozbe/zacs'
import style from './style'

const Box = zacs.view(style.box, { isHighlighted: style.highlighted })

const rendered = <Box isHighlighted />

Into optimized code that looks like this (web):

const rendered = <div className={style.box + ' ' + style.highlighted} />

Or this (React Native):

import { View } from 'react-native'

const rendered = <View style={[style.box, style.highlighted]} />

Pitch

ZACS (Zero Abstraction Cost Styling) is a super-fast component styling library for cross-platform React web and React Native apps.

Super-fast as in: there is no difference between using ZACS and writing <div className> and <View style> manually. That's because the library doesn't actually exist at runtime, it's entirely implemented as a Babel plugin, which compiles the "styled components" syntax down to bare metal.

And because ZACS hides the API difference between web (DOM) and React Native, you can build a web and RN app with shared codebase without react-native-web.

Installation

npm install @nozbe/zacs

or

yarn add @nozbe/zacs

Then add ZACS to your Babel config (.babelrc or babel.config.js):

{
  "plugins": [
+   ["@nozbe/zacs/babel", {
+     "platform": "web", // "web" or "native"
+     "production": false / true, // pass `false` to enable debug attributes
+     "keepDeclarations": false // (optional) pass `true` to keep zacs.xxx variable declarations in output
+   }]
  ]
}

Using zacs

Unstyled view or text

import zacs from '@nozbe/zacs'

const Box = zacs.view() // or zacs.view(null)
const Label = zacs.text()

const rendered = <Box><Label>Hello</Label></Box>
<details> <summary>See compiled output</summary>

Web:

const rendered = <div><span>Hello</span></div>

React Native:

import { View, Text } from 'react-native'

const rendered = <View><Text>Hello</Text></View>
</details>

Simple styled view or text

import styles from './styles'

const Box = zacs.view(styles.box) // or zacs.text

const rendered = <Box />
<details> <summary>See compiled output</summary>

Web:

const rendered = <div className={styles.box} />

React Native:

import { View } from 'react-native'

const rendered = <View style={styles.box} />
</details>

Conditional styles

const Box = zacs.view(styles.box, {
  isHighlighted: styles.isHighlighted,
  isVisible: styles.isVisible,
})

const rendered = <Box isHighlighted={reactions > 0} isVisible />

Declare conditional styles as { [propName: string]: RNStyleOrClassName }. If a specified prop is passed to the component with a truthy value, the corresponding style will be added.

<details> <summary>See compiled output</summary>

Web:

const rendered = <div className={styles.box
                                + ' ' + styles.isVisible
                                + (reactions > 0) ? (' ' + styles.isHighlighted) : ''} />

Please note:

  • conditions are inlined whenever possible (when a constant is passed to a styling prop)
  • styling props are removed from the compiled output

React Native:

import { View } from 'react-native'

const rendered = <View style={[styles.box,
                              styles.isVisible,
                              reactions > 0 && styles.isHighlighted]} />
</details>

Adding style attributes (via individual props)

const Box = zacs.view(styles.box, null, {
  width: 'width',
  color: 'backgroundColor',
})

const rendered = <Box width={100} color="#80EADC" />

Declare CSS / React Native StyleSheet attributes available as component properties with { [propName: string]: CSSOrRNStyleAttributeName }.

Gotcha: If you pass a style attribute at all, it will override the main and conditional styles, even if the value is undefined.

<details> <summary>See compiled output</summary>

Web:

const rendered = <div className={styles.box} style={{ width: 100, backgroundColor: '#80EADC' }} />

React Native:

import { View } from 'react-native'

const rendered = <View style={[styles.box, { width: 100, backgroundColor: '#80EADC' }]} />
</details>

Adding styles directly

const Box = zacs.view(styles.box)

const rendered = <Box zacs:style={{ width: 100, color: '#80EADC' }} />

This is equivalent to the example above, but instead of predefining list of props that turn into styles, we pass styles directly. Note that this only works on ZACS components.

Multiple unconditional styles

import styles from './styles'

const TitleText = zacs.text([styles.text, styles.titleText])

const rendered = <TitleText />
<details> <summary>See compiled output</summary>

Web:

const rendered = <span className={styles.text + ' ' + styles.titleText} />

React Native:

import { Text } from 'react-native'

const rendered = <Text style={[styles.text, styles.titleText]} />
</details>

Styling custom components

import Touchable from 'components/Touchable'

const Button = zacs.styled(Touchable, styles.button, null, {
  width: 'width'
})

const rendered = <Button width={500} />
<details> <summary>See compiled output</summary>

Web:

import Touchable from 'components/Touchable'

const rendered = <Touchable className={styles.button} style={{ width: 500 }} />

React Native:

import Touchable from 'components/Touchable'

const rendered = <Touchable style={[styles.button, { width: 500 }]} />
</details>

Making stylable components

To define new components that you can style using zacs.styled, use the special zacs:inherit prop to let ZACS know you want styles from props.style / props.className added in.

const Root = zacs.view(styles.root)

export default const Touchable = props => {
  return <Root zacs:inherit={props} />
}
<details> <summary>See compiled output</summary>

Web:

export default const Touchable = props => {
  return <div className={styles.root + ' ' + (props.className || '')} style={props.style} />
}

React Native:

import { View } from 'react-native'

export default const Touchable = props => {
  return <View style={[styles.root].concat(props.style || [])} />
}
</details>

Configuring output component/element types

Sometimes you need to style a different component on web and native. To do this, use zacs.styled with { web: ComponentType, native: ComponentType } instead of a direct component reference.

const Paragraph = zacs.styled({ web: 'p', native: zacs.text }, styles.paragraph)

const rendered = <Paragraph>Hello world!</Paragraph>

As parameters, you can pass:

  • built in element type (string - p, div, form)
  • a component reference
  • magic zacs.text or zacs.view (this is so you can easily fall back to RN View/Text without importing react-native)

If you're only building for one platform, you can also reference built-ins like this:

const Paragraph = zacs.styled('p', styles.paragraph) // NOTE: No web/native, because this is web-only code

TODO: Passing zacs.text/view as parameter seems magic and gross. If you have a better idea for this API, let us know!

<details> <summary>See compiled output</summary>

Web:

const rendered = <p className={styles.paragraph}>Hello world!</p>

React Native:

import { Text } from 'react-native'

const rendered = <Text style={styles.paragraph}>Hello world!</Text>
</details>

Exporting ZACS components

zacs.view/text/styled are special declarations for the compiler, not real components — that's the whole point of "zero abstraction cost styling".

Unfortunately, this means that you can only use those components in the same file in which they're defined, and you can't export it. And this is how you should use zacs most of the time. But sometimes, to avoid repetitive code, you really need this.

In that case, use zacs.createView/Text/Styled, which actually creates a real component:

export const Box = zacs.createView(styles.box)
export const Label = zacs.createText(styles.label, {
  isBold: style.labelBold,
}, null, ['title', 'numberOfLines'])
export const Wrapper = zacs.createView(styles.wrapper, null, null, ['ref'])

You must declare (in the last argument) all non-zacs props you want to be able to pass into the component you're styling (component props, DOM attributes, ref, and zacs:inherit

Related Skills

View on GitHub
GitHub Stars431
CategoryDevelopment
Updated8mo ago
Forks8

Languages

JavaScript

Security Score

92/100

Audited on Jul 15, 2025

No findings