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><Headinglevel="4">Title</Heading><Text>My first Braid component</Text><Button>Click me</Button></Card>
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><Stackspace="small"><Headinglevel="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><Stackspace={{ mobile:"small", tablet:"medium"}}><Headinglevel="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
<Columnsspace="gutter"collapseBelow="tablet"><Column><Card><Stackspace="small"><Headinglevel="4">Column 1</Heading><Text>My first Braid component</Text></Stack></Card></Column><Column><Card><Stackspace="small"><Headinglevel="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
<Columnsspace={{ mobile:"xxsmall", tablet:"gutter"}}collapseBelow="tablet"><Column><Card><Stackspace="small"><Headinglevel="4">Column 1</Heading><Text>My first Braid component</Text></Stack></Card></Column><Column><Card><Stackspace="small"><Headinglevel="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
<Boxbackground="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
<Boxdisplay={{ mobile:"flex", tablet:"block"}}><Headinglevel="2">Flex on small screen</Heading><Headinglevel="2">Block on large screen</Heading></Box>
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:
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:
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:
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.tsimport*as styles from"./myComponent.css"exportdefaultfunctionMyComponent(){return(<Boxdisplay="flex"className={styles.root}><Text>My first Braid component</Text></Box>)}