Development Workflow

This document aims to provide guidance for consumers on how best to build interfaces that properly leverage Braid.

Working with components

Braid provides consumers with a suite of components that are powered by an underlying themed styling system.
The idealistic goal is that consumers should be able to build their experiences entirely from Braid components—using only the prop interfaces they expose. If done correctly, our products should be expressed exclusively using the design system’s language, which inherently means that they can be adapted to any theme that Braid supports.
However, it’s expected that you’ll find gaps in the system, so Braid also provides lower level building blocks for generating custom components.

High level components

Braid’s high level components are most likely the ones you would come to expect from a design system, e.g. Text, Heading, Card, Button, TextField, etc.
For these high level components, we have opted against supporting style overrides via ‘className’ and ‘style’ props. This ensures that gaps in the design system are surfaced rather than encouraging consumers to constantly apply workarounds.
An example of composing a simple view leveraging some of these could be:
<Card>
  <Heading level="4">Title</Heading>
  <Text>My first Braid component</Text>
  <Button>Click me</Button>
</Card>
You’ll notice that each of these components don’t provide any surrounding white space. This is where our layout components come in.

Layout components

In order to distribute white space evenly between components, wrap sibling elements in a Stack component with a custom ‘space’ property. For example, if you wanted ‘small’ space between items in a Stack:
<Card>
  <Stack space="small">
    <Heading level="4">Title</Heading>
    <Text>My first Braid component</Text>
    <Button>Click me</Button>
  </Stack>
</Card>
The ‘space’ property is a responsive prop, which means that it can also accept an array of values representing each breakpoint. For example, if you wanted ‘small’ space on mobile and ‘medium’ space on desktop:
<Card>
  <Stack space={["small", "medium"]}>
    <Heading level="4">Title</Heading>
    <Text>My first Braid component</Text>
    <Button>Click me</Button>
  </Stack>
</Card>
For horizontal layouts, Columns provides various responsive rules for laying out content. For example, if you wanted to render a two-column layout that collapses to a single column on mobile:
<Columns space="gutter" collapse>
  <Column>
    <Card>
      <Stack space="small">
        <Heading level="4">Column 1</Heading>
        <Text>My first Braid component</Text>
      </Stack>
    </Card>
  </Column>
  <Column>
    <Card>
      <Stack space="small">
        <Heading level="4">Column 2</Heading>
        <Text>My second Braid component</Text>
      </Stack>
    </Card>
  </Column>
</Columns>
This ‘space’ property is also responsive, supporting an array of values for each breakpoint. For example, if you wanted ‘xxsmall’ space on mobile and ‘gutter’ space on desktop:
<Columns space={["xxsmall", "gutter"]} collapse>
  <Column>
    <Card>
      <Stack space="small">
        <Heading level="4">Column 1</Heading>
        <Text>My first Braid component</Text>
      </Stack>
    </Card>
  </Column>
  <Column>
    <Card>
      <Stack space="small">
        <Heading level="4">Column 2</Heading>
        <Text>My second Braid component</Text>
      </Stack>
    </Card>
  </Column>
</Columns>

Need a custom component?

If you’re unable to satisfy a design using the built-in set of higher level components, Braid also provides consumers with the Box component that provides direct access to the themed atomic styles that Braid uses internally, without the overhead of having to create and import a separate style sheet. A nice side-effect of this approach is that your application will be reusing existing CSS rules rather than generating new ones, keeping your bundle size to a minimum.
The prop names for Box mostly mimic standard CSS properties, while their values are more semantic, allowing the corresponding CSS rules to be computed across themes.
<Box background="brand" boxShadow="large" padding="large">
  <Text>My first Braid component</Text>
</Box>
For more details, view the complete Box documentation. For TypeScript users, you should also find that the Box API is available for autocompletion and type checking within your editor.

Need responsive styles?

Previously, one of the main reasons for needing to create custom CSS was to define responsive rules. The Box component makes this possible via responsive properties, which are provided as an array of values—one per defined breakpoint, where the first item is the mobile value, followed by the desktop value.
For example, if we wanted to change the value for ‘display’ responsively:
<Box display={["flex", "block"]}>
  <Heading level="2">Flex on small screen</Heading>
  <Heading level="2">Block on large screen</Heading>
</Box>
For a list of low-level responsive props, check out the Box documentation.

Need semantic markup?

A key difference with Braid is that it doesn’t use a standard global CSS reset. Instead, element styles are reset at the component level via Box and its ‘component’ prop.
For example, in order to render a semantic ‘fieldset’ element without the native browser styles:
<Box component="fieldset">
  <legend>Reset Fieldset</legend>
</Box>

Still need custom CSS?

Braid is built on top of treat (imported via ‘sku/treat’ which satisfies our requirements for themeable, statically extracted CSS. Custom styles on top of Braid should use treat in order to gain access to the underlying theme variables.
Before writing a treat file, we highly recommend that you read the treat documentation.
While higher level Braid components don’t support custom style overrides (e.g. ‘className’ and ‘style’), Box is the one exception. However, you should take care to ensure that custom classes on Box only use styles that are not available via its prop interface.
For example, if you wanted to render an element as ‘display: flex’, but with a custom, responsive ‘flex-basis’ value:
// myComponent.treat.ts
import { style } from "sku/treat"

export const root = style(theme =>
  theme.utils.responsiveStyle({
    mobile: { flexBasis: theme.grid * 3 },
    tablet: { flexBasis: theme.grid * 5 },
    desktop: { flexBasis: theme.grid * 8 }
  })
)
Because treat files are written in TypeScript, the ‘theme’ object will be available for autocompletion and type checking within your editor.
// myComponent.ts
import { useStyles } from "sku/react-treat"
import * as styleRefs from "./myComponent.treat.ts"

export default () => {
  const styles = useStyles(styleRefs)

  return (
    <Box display="flex" className={styles.root}>
      <Text>My first Braid component</Text>
    </Box>
  )
}

Have a question that wasn’t answered?

Reach out to us in #braid-support.