Development Workflow

This document aims to provide guidance for consumers on how best to build interfaces that properly leverage Braid.
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.
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:

Title

My first Braid component
<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.
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 wantedsmall space between items in a Stack:

Title

My first Braid component
<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 different values for each breakpoint. For example, if you wanted small space on mobile and medium space on tablet and above:

Title

My first Braid component
<Card>
  <Stack space={{ mobile: "small", tablet: "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:

Column 1

My first Braid component

Column 2

My second Braid component
<Columns space="gutter" collapseBelow="tablet">
  <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 values that differ by breakpoint. For example, if you wanted xxsmall space on mobile and gutter space on tablet and above:

Column 1

My first Braid component

Column 2

My second Braid component
<Columns
  space={{ mobile: "xxsmall", tablet: "gutter" }}
  collapseBelow="tablet"
>
  <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>
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.
My first Braid component
<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.
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 allows different values to specified for each defined breakpoint.
For example, if we wanted to change the value for display responsively:

Flex on small screen

Block on large screen

<Box display={{ mobile: "flex", tablet: "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.
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:
Reset Fieldset
<Box component="fieldset">
  <legend>Reset Fieldset</legend>
</Box>
Braid is built on top of vanilla-extract which satisfies our requirements for statically extracted CSS, leveraging CSS variables for theming. Custom styles on top of Braid can access the theme variables by importing them from Braid’s css export:
import { vars } from "braid-design-system/css"
Before writing custom styles, we highly recommend that you read the vanilla-extract 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.css.ts
import { style } from "@vanilla-extract/css"
import { vars, responsiveStyle } from "braid-design-system/css"

export const root = style(
  responsiveStyle({
    mobile: { flexBasis: vars.space.small },
    tablet: { flexBasis: vars.space.medium },
    desktop: { flexBasis: vars.space.large },
    wide: { flexBasis: vars.space.xlarge },
  })
)
Because vanilla-extract stylesheets are written in TypeScript (note the.css.ts extension), the vars object will be available for autocompletion and type checking within your editor.
// myComponent.ts
import * as styles from "./myComponent.css"

export default function MyComponent() {
  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.