customization
patterns

Customizing Patterns

Bamboo provides the ability to customize the built-in patterns, as well as creating your own custom patterns. This is useful to create your own layout pattern abstractions that can be used in your application.

Bamboo allows you to customize built-in patterns and create custom patterns for reusable layout abstractions.

A pattern accepts the following parameters:

  • description - The description of the pattern.
  • properties - The list of properties that the pattern accepts.
  • defaultValues - The default values for the properties. This is useful when you want to provide a default value for a property.
  • transform - The function that accepts the properties and a set of helpers, and returns a css object.
  • cssProps - Which css properties the pattern accepts beside its own: 'all', 'none', or { except: [...] }. Can be used to ensure strict typings when using the pattern.
  • strict - Whether to only generate types for the specified properties. This will disallow css properties.

Transform helpers

transform receives a second argument with everything it needs to shape values it cannot inspect itself:

helperreturns
map(value, fn)fn applied to a value, or to each leaf of a conditional one
token(path, fallback?)the css variable for a token path, or fallback when the path names no token
isCssUnit(value)whether the value is a css length, e.g. 10px
isCssVar(value)whether the value is a var(...) reference
isCssFunction(value)whether the value is a css function call

token is what lets a pattern accept either a token name or a raw css value, which is how the built-in bleed, grid and spacer patterns work:

transform(props, { token, isCssUnit }) {
  // '4' → var(--spacing-4) · 'auto' → auto · '10px' → 10px
  const value = isCssUnit(props.size) ? props.size : token(`spacing.${props.size}`, props.size)
  return { flex: `0 0 ${value}` }
}

Resolve the token here rather than emitting a reference for the css pipeline to read later — the build, the extractor and the browser all answer through this helper, so the value a pattern produces is the same in each.

Creating a Pattern

To create a pattern, you can use the patterns property in the config. Let's say we want to create a "Scrollable" pattern that applies preset styles to a container that allows for scrolling.

const config = {
  patterns: {
    extend: {
      scrollable: {
        description: 'A container that allows for scrolling',
        defaultValues: {
          direction: 'vertical',
          hideScrollbar: true,
        },
        properties: {
          // The direction of the scroll
          direction: { type: 'enum', value: ['horizontal', 'vertical'] },
          // Whether to hide the scrollbar
          hideScrollbar: { type: 'boolean' },
        },
        // disallow the `overflow` property (in TypeScript)
        cssProps: { except: ['overflow'] },
        transform(props) {
          const { direction, hideScrollbar, ...rest } = props
          return {
            overflow: 'auto',
            height: direction === 'horizontal' ? '100%' : 'auto',
            width: direction === 'vertical' ? '100%' : 'auto',
            scrollbarWidth: hideScrollbar ? 'none' : 'auto',
            WebkitOverflowScrolling: 'touch',
            '&::-webkit-scrollbar': {
              display: hideScrollbar ? 'none' : 'auto',
            },
            ...rest,
          }
        },
      },
    },
  },
}

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

pnpm bamboo codegen

Now you can import the pattern and use it in your application:

import { scrollable } from '../styled-system/patterns'
 
const App = () => {
  return (
    <div className={scrollable({ direction: 'vertical', hideScrollbar: true })}>
      <div>Scrollable content</div>
    </div>
  )
}

Customizing Built-in Patterns

You can extend the default patterns by using the patterns.extend property in the config.

bamboo.config.ts

import { defineConfig } from '@bamboocss/dev'
 
export default defineConfig({
  patterns: {
    extend: {
      // Extend the default `flex` pattern
      flex: {
        properties: {
          // only allow row and column
          direction: { type: 'enum', value: ['row', 'column'] },
        },
      },
    },
  },
})

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

pnpm bamboo codegen