---
title: Responsive Design
description: How to write mobile responsive designs in your CSS in Bamboo
---

Bamboo expresses responsive styles as conditional styles keyed by breakpoint.

Let's say you want to change the font weight of a text on large screens, you can do it like this:

```jsx
<span
  className={css({
    fontWeight: 'medium',
    lg: { fontWeight: 'bold' },
  })}
>
  Text
</span>
```

> Bamboo uses a mobile-first breakpoint system, and writes responsive styles as lower-bounded range queries —
> `@media (width >= 40rem)`. Ranges that also have an upper bound close it exclusively,
> `@media (width >= 40rem) and (width < 48rem)`, so a range stops exactly where the next one starts.

> Range syntax needs Chrome 104+, Safari 16.4+ or Firefox 102+. The
> [`lightningcss`](/docs/references/config#lightningcss) option lowers these queries against your browserslist targets,
> which recovers most of that: a plain breakpoint becomes `(min-width: …)` again, but an exclusive upper bound has no
> older spelling and lowers to `not (min-width: …)`, so `smDown`, `mdOnly` and `mdToXl` still need roughly Chrome 88 /
> Safari 14 / Firefox 64.

> These queries carry no media type, so unlike the `@media screen and …` Bamboo emitted previously, responsive styles
> now also apply when printing — against the page width. Wrap rules you want to keep off the printed page in an explicit
> `@media screen`.

Bamboo provides five breakpoints by default:

```ts
const breakpoints = {
  sm: '640px',
  md: '768px',
  lg: '1024px',
  xl: '1280px',
  '2xl': '1536px',
}
```

## Overview

### Property based modifier

Bamboo allows you apply the responsive condition directly to a style property, resulting in a more concise syntax:

```diff
<span
  className={css({
-   fontWeight: 'medium',
-   lg: { fontWeight: 'bold' }
+   fontWeight: { base: 'medium', lg: 'bold' }
  })}
>
  Text
</span>
```

### Why there is no array syntax

An earlier version also read an array as one value per breakpoint —
`fontWeight: ['medium', undefined, undefined, 'bold']`. It has been removed, and an array in a style value is now an
error naming the property it was written on.

It was the worse of the two spellings on its own terms: positional, so it needed `undefined` padding to skip a
breakpoint, and it re-pointed every value if you inserted a breakpoint above them. But the reason it had to go is that
CSS already writes lists as arrays, so a font stack written the obvious way —

```js
css({ fontFamily: ['Inter', 'sans-serif'] })
```

— quietly compiled to `Inter` at base and `sans-serif` at `sm`. No error, no warning, and nothing in the type to suggest
it. Write the condition object instead:

```js
css({ fontWeight: { base: 'medium', lg: 'bold' } })
```

### Targeting a breakpoint range

By default, styles assigned to a specific breakpoint will be effective at that breakpoint and will persist as applied
styles at larger breakpoints.

If you wish to apply a utility exclusively when a particular range of breakpoints is active, Bamboo offers properties
that restrict the style to that specific range. To construct the property, combine the minimum and maximum breakpoints
using the "To" notation in camelCase format.

Let's say we want to apply styles between the `md` and `xl` breakpoints, we use the `mdToXl` property:

```jsx
<span
  className={css({
    fontWeight: { mdToXl: 'bold' },
  })}
>
  Text
</span>
```

> This text will only be bold in the `md` and `lg` breakpoints. The upper bound is exclusive: `mdToXl` stops where `xl`
> starts, so it emits `(width >= 48rem) and (width < 80rem)`.

### Targeting a single breakpoint

To target a single breakpoint, you can easily achieve this by simply adding the suffix "Only" to the breakpoint name in
camelCase format.

Let's say we want to apply styles only in the `lg` breakpoint, we use the `lgOnly` property:

```jsx
<span
  className={css({
    fontWeight: { lgOnly: 'bold' },
  })}
>
  Text
</span>
```

### Customizing Breakpoints

Define custom breakpoints by passing them as an object in your Bamboo config.

> Note: Make sure that the CSS units of your breakpoints are consistent. Use either all pixels (`px`) or all `em`, but
> do not mix them.

```js filename="bamboo.config.ts"
import { defineConfig } from '@bamboocss/dev'

export default defineConfig({
  // ...
  theme: {
    extend: {
      breakpoints: {
        sm: '640px',
        md: '768px',
        lg: '1024px',
        xl: '1280px',
        '2xl': '1536px',
      },
    },
  },
})
```

### Hiding elements by breakpoint

Set `display` under the range you want it hidden in — `md: { display: 'none' }` from `md` up, `mdDown` below it. See
[Display](/docs/utilities/display#hiding-elements) for the worked forms.
