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.
New

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
Open in Playroom

How do I build this example for myself?

Designs like this are rarely built top-to-bottom in a single pass. Instead, they typically start very simple, with further details and refinements added in layers.To give you a sense of what this looks like, the following tutorial will guide you through the design process that you might go through when using Playroom.At any stage you can click the “Open in Playroom” button under the examples to view the design across themes and viewports.

1. Create card with basic content

Adding the basic content up front is a great place to start, allowing us to consider the hierarchy of information as we iterate. We’ll nest this content inside a Card and apply some basic formatting using Heading and Text.

Product Designer

Braid Design Pty LtdMelbourneInformation Technology150k+Long description of card details providing more information.2d ago
<Card>
  <Heading level="4">Product Designer</Heading>
  <Text>Braid Design Pty Ltd</Text>
  <Text>Melbourne</Text>
  <Text>Information Technology</Text>
  <Text>150k+</Text>
  <Text>Long description of card details providing more information.</Text>
  <Text>2d ago</Text>
</Card>

2. Space out the content

You’ll notice that there is no space between components by default. This is actually a good thing! We now get to decide exactly how spaced out we want the content to be. To achieve this, we’ll use a Stack component which applies space evenly between its child elements.

Product Designer

Braid Design Pty LtdMelbourneInformation Technology150k+Long description of card details providing more information.2d ago
<Card>
  <Stack space="large">
    <Heading level="4">Product Designer</Heading>
    <Text>Braid Design Pty Ltd</Text>
    <Text>Melbourne</Text>
    <Text>Information Technology</Text>
    <Text>150k+</Text>
    <Text>Long description of card details providing more information.</Text>
    <Text>2d ago</Text>
  </Stack>
</Card>

3. Group content

Grouping the content into sections can help provide structure to the information, and in turn, make it easier to digest. Let’s divide the information into four descrete sections — the header, metadata, body and footer. For this, we’ll start nesting new Stack components within our existing Stack. (Yeah, we realise this is a little mind bending at first!)

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
<Card>
  <Stack space="large">
    <Stack space="small">
      <Heading level="4">Product Designer</Heading>
      <Text>Braid Design Pty Ltd</Text>
    </Stack>

    <Stack space="small">
      <Text>Melbourne</Text>
      <Text>Information Technology</Text>
      <Text>150k+</Text>
    </Stack>

    <Text>Long description of card details providing more information.</Text>

    <Text>2d ago</Text>
  </Stack>
</Card>

4. Use size and tone to provide hierarchy

Not all the information presented has the same priority. To improve readability, we can adjust the tone and/or the size of the information. In this case, pushing some details back to “secondary” and/or reducing their size can help focus the user’s attention.

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
<Card>
  <Stack space="large">
    <Stack space="small">
      <Heading level="4">Product Designer</Heading>
      <Text>Braid Design Pty Ltd</Text>
    </Stack>

    <Stack space="small">
      <Text tone="secondary">Melbourne</Text>
      <Text tone="secondary">Information Technology</Text>
      <Text tone="secondary">150k+</Text>
    </Stack>

    <Text>Long description of card details providing more information.</Text>

    <Text tone="secondary" size="small">
      2d ago
    </Text>
  </Stack>
</Card>

5. Add icons

Icons can be used to serve as visual cues to complement data and introduce some more visual interest. Let’s add icons to our list of metadata.

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
<Card>
  <Stack space="large">
    <Stack space="small">
      <Heading level="4">Product Designer</Heading>
      <Text>Braid Design Pty Ltd</Text>
    </Stack>

    <Stack space="small">
      <Text tone="secondary" icon={<IconLocation />}>
        Melbourne
      </Text>
      <Text tone="secondary" icon={<IconTag />}>
        Information Technology
      </Text>
      <Text tone="secondary" icon={<IconMoney />}>
        150k+
      </Text>
    </Stack>

    <Text>Long description of card details providing more information.</Text>

    <Text tone="secondary" size="small">
      2d ago
    </Text>
  </Stack>
</Card>

6. Add a splash of colour

Let’s look at adding a visual cue to indicate that this job is new. To do this, we’ll add a Badge component to the top of our card.
New

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
<Card>
  <Stack space="large">
    <Stack space="small">
      <Badge tone="positive">New</Badge>
      <Heading level="4">Product Designer</Heading>
      <Text>Braid Design Pty Ltd</Text>
    </Stack>

    <Stack space="small">
      <Text tone="secondary" icon={<IconLocation />}>
        Melbourne
      </Text>
      <Text tone="secondary" icon={<IconTag />}>
        Information Technology
      </Text>
      <Text tone="secondary" icon={<IconMoney />}>
        150k+
      </Text>
    </Stack>

    <Text>Long description of card details providing more information.</Text>

    <Text tone="secondary" size="small">
      2d ago
    </Text>
  </Stack>
</Card>
Let’s also add a Rating alongside the company name. Ideally we want this to sit on the same line, but if it does not fit due to the length of the name or the size of the screen we want it to wrap below. For this we can use the Inline component.NOTE: Click through to the Playroom to see how this behaves across screen sizes.
New

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
<Card>
  <Stack space="large">
    <Stack space="small">
      <Badge tone="positive">New</Badge>
      <Heading level="4">Product Designer</Heading>
      <Inline space="small" alignY="center">
        <Text>Braid Design Pty Ltd</Text>
        <Rating rating={4.5} />
      </Inline>
    </Stack>

    <Stack space="small">
      <Text tone="secondary" icon={<IconLocation />}>
        Melbourne
      </Text>
      <Text tone="secondary" icon={<IconTag />}>
        Information Technology
      </Text>
      <Text tone="secondary" icon={<IconMoney />}>
        150k+
      </Text>
    </Stack>

    <Text>Long description of card details providing more information.</Text>

    <Text tone="secondary" size="small">
      2d ago
    </Text>
  </Stack>
</Card>

7. Add an action to the corner of the card

Sometimes adding new features can necessitate changing the layout. First, we’ll use a Spread component to separate our content and action.NOTE: To make this easier to follow, we’ve replaced the job content with a Placeholder.
Job content
Save action
<Card>
  <Spread space="small">
    <Placeholder label="Job content" height={80} />
    <Placeholder label="Save action" height={80} />
  </Spread>
</Card>
For the save action we’ll use a ButtonIcon with an IconBookmark. We can now replace our “Save action” Placeholder with the ButtonIcon.
Job content
<Card>
  <Spread space="small">
    <Placeholder label="Job content" height={80} />
    <ButtonIcon
      variant="transparent"
      size="large"
      icon={<IconBookmark />}
      label="Save job"
    />
  </Spread>
</Card>
Now that we’ve added the action, let’s reinstate our content by replacing the “Job content” Placeholder.
New

Product Designer

Braid Design Pty Ltd
MelbourneInformation Technology150k+
Long description of card details providing more information.2d ago
<Card>
  <Spread space="small">
    <Stack space="large">
      <Stack space="small">
        <Badge tone="positive">New</Badge>
        <Heading level="4">Product Designer</Heading>
        <Inline space="small" alignY="center">
          <Text>Braid Design Pty Ltd</Text>
          <Rating rating={4.5} />
        </Inline>
      </Stack>

      <Stack space="small">
        <Text tone="secondary" icon={<IconLocation />}>
          Melbourne
        </Text>
        <Text tone="secondary" icon={<IconTag />}>
          Information Technology
        </Text>
        <Text tone="secondary" icon={<IconMoney />}>
          150k+
        </Text>
      </Stack>

      <Text>Long description of card details providing more information.</Text>

      <Text tone="secondary" size="small">
        2d ago
      </Text>
    </Stack>
    <ButtonIcon
      variant="transparent"
      size="large"
      icon={<IconBookmark />}
      label="Save job"
    />
  </Spread>
</Card>
Now that we have all our elements in place we can polish until we are happy. Adjusting white space between elements, or even responsively, to achieve the desired goal.

Next steps

Now that you are familiar with the code we have just written, this is a good chance to head over to Playroom and continue refining this design.You may want to consider:
  • Using Hidden to reduce the amount of data shown on mobile,
  • Specifying different spacing responsively using Stack,
  • Adding a company logo. You can use Placeholder component if you don’t have hosted imagery to work with.

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.
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.

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 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.

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:
Reset Fieldset
<Box component="fieldset">
  <legend>Reset Fieldset</legend>
</Box>

Still need custom CSS?

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.