customization
utilities

Utilities

The utility API is a way to create your own CSS properties, map existing properties to a set of values or tokens.

The utility API enables you to create custom CSS properties and map existing properties to specific values or tokens. It's like building your own type-safe version of Chakra UI, Tailwind (in JS), or Styled System.

Bamboo comes with a set of utilities out of the box. You can customize them, or add your own.

Here are the properties you need to define or customize a utility:

  • className : The className the property maps to
  • shorthand: The shorthand or alias version of the property
  • values: The possible values the property can have. Could be a token category, or an enum of values, string, number, or boolean.
  • transform: A function that converts the value to a valid css object
  • property: The css property this utility maps to. Its accepted values are added to the utility's own type, unless strictValues is on.
  • group: The semantic group the utility belongs to, used to organise generated documentation.
  • deprecated: Whether the utility is deprecated. See Deprecations.
  • customProperties: Custom properties this utility composes its value from, registered with @property. Several utilities build one declaration out of many variables — filter out of nine, translate out of its axes — while a sibling utility sets each variable on its own. Declaring them here is what registers them, so the utility that reads a variable is the thing that guarantees it exists, and registration is merged across every configured utility. Omitting initialValue gives the property the guaranteed-invalid value, which is what a var(--x, ) reference expects; a variable read without a fallback needs one declared instead, or the whole declaration is invalid.

Creating a custom utility

Let's say we want to create new property br that applies a border radius to an element.

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  utilities: {
    extend: {
      br: {
        className: 'rounded', // css({ br: "sm" }) => rounded-sm
        values: 'radii', // connect values to the radii tokens
        transform(value) {
          return { borderRadius: value }
        },
      },
    },
  },
})

Then you can run the following command to generate the pattern JS code:

pnpm bamboo codegen

Now, we can use the br property in our components.

import { css } from '../styled-system/css'
 
function App() {
  return <div className={css({ br: 'sm' })} />
}

Using enum values

Let's say we want to create a new property borderX that applies a limited set of inline border to an element and automatically applies the border color.

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  utilities: {
    extend: {
      borderX: {
        values: ['1px', '2px', '4px'],
        shorthand: 'bx', // `bx` or `borderX` can be used
        transform(value, { token }) {
          return {
            borderInlineWidth: value,
            borderColor: token('colors.red.200'), // read the css variable for red.200
          }
        },
      },
    },
  },
})

Now, we can use the borderX or bx property in our components.

import { css } from '../styled-system/css'
 
function App() {
  return <div className={css({ borderX: '2px' })} />
}

Using mapped values

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  utilities: {
    extend: {
      borderX: {
        values: { small: '2px', medium: '5px' },
        shorthand: 'bx',
        transform(value, { token }) {
          return {
            borderTopWidth: value,
            borderTopColor: token('colors.gray.400'),
          }
        },
      },
    },
  },
})

Using boolean values

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  utilities: {
    extend: {
      truncate: {
        className: 'truncate',
        values: { type: 'boolean' },
        transform(value) {
          if (!value) return {}
          return {
            overflow: 'hidden',
            textOverflow: 'ellipsis',
            whiteSpace: 'nowrap',
          }
        },
      },
    },
  },
})