Guide

Responsive System

Config-driven breakpoints, responsive object syntax, and $-prefixed breakpoint props — all fully typed from your createUi configuration.

Overview

Stareezy UI's responsive system is driven by your stareezy.config.ts. Declare breakpoints once in createUi({ media }) and TypeScript automatically derives the valid breakpoint keys — so autocomplete and type errors work everywhere without extra setup.

Breakpoints are mobile-first and resolved as min-width media queries on web, and as window-width comparisons on React Native.

Declaring breakpoints with createUi

Pass a media record to createUi(). Keys are breakpoint names, values are min-width thresholds in pixels.

// stareezy.config.ts
import { createUi, themes } from '@stareezy-ui/tokens'

export const ui = createUi({
  themes: { aurora: themes.aurora, light: themes.light },

  // Declare your responsive breakpoints (mobile-first, min-width px)
  media: {
    sm:  480,
    md:  768,
    lg:  1024,
    xl:  1280,
    '2xl': 1536,
  },

  // Optional — custom shorthands that also accept responsive values
  shorthands: {
    p:  'padding',
    px: 'paddingHorizontal',
    py: 'paddingVertical',
    m:  'margin',
    br: 'borderRadius',
    w:  'width',
    h:  'height',
  } as const,
})

// Module augmentation — makes breakpoints and shorthands flow into the type system
type AppConfig = typeof ui
declare module '@stareezy-ui/tokens' {
  interface SzrCustomConfig extends AppConfig {}
}

export default ui
createUi({ media }) automatically syncs the declared breakpoints into the runtime — no separate configureBreakpoints() call is needed.

Config-driven BreakpointKey autocomplete

After the module augmentation above, BreakpointKey is derived directly from your media configuration. TypeScript autocompletes only the keys you declared, and reports a type error for any other key.

// After augmenting SzrCustomConfig with the config above,
// BreakpointKey = "base" | "sm" | "md" | "lg" | "xl" | "2xl"

// ✅ Valid — these keys match the declared breakpoints
<Box p={{ base: 8, md: 16, lg: 24 }} />

// ❌ Type error — "tablet" is not a declared breakpoint
<Box p={{ tablet: 16 }} />
//        ↑ Type '"tablet"' is not assignable to type 'BreakpointKey'

Without augmentation, the default BreakpointKey is "base" | "sm" | "md" | "lg" | "xl" | "2xl".

Responsive object syntax

Pass a { base?, sm?, md?, lg?, xl?, '2xl'? } object to any layout or shorthand prop. The base value applies unconditionally; each named breakpoint applies at and above its configured threshold (mobile-first).

import { Box, Button, Card } from '@stareezy-ui/components'

// Responsive padding
<Box p={{ base: 8, md: 16, lg: 24 }} />

// Responsive width — full on mobile, auto on desktop
<Button w={{ base: '100%', md: 'auto' }} />

// Responsive flex direction
<Box
  flexDirection={{ base: 'column', lg: 'row' }}
  gap={{ base: 8, lg: 16 }}
>
  <Card p={{ base: 12, md: 20 }} />
  <Card p={{ base: 12, md: 20 }} />
</Box>

▸ Responsive object syntax — Every layout prop accepts a { base?, sm?, md?, lg?, xl?, '2xl'? } object. The base value applies unconditionally; each named breakpoint activates at and above its min-width threshold.

Responsive values on custom shorthands

Custom shorthands declared through createUi({ shorthands }) accept responsive objects with the same syntax as built-in props.

// With the shorthands declared above:
<Box br={{ base: 4, md: 8, lg: 12 }} />  // borderRadius responsive
<Box px={{ base: 12, lg: 24 }} />        // paddingHorizontal responsive
<Box w={{ base: '100%', md: 320 }} />    // width responsive

// Mix responsive and plain values
<Box p={{ base: 8, md: 16 }} br={8} w="100%" />

$-prefixed breakpoint-as-prop syntax

As an alternative to responsive objects, you can group multiple style props under a single $breakpoint key (Tamagui-style). Each $-prefixed prop accepts a partial set of Box style and shorthand props scoped to that breakpoint.

// Equivalent to writing individual responsive objects on each prop
<Box
  $md={{ p: 16, br: 8 }}
  $lg={{ p: 24, br: 12, flexDirection: 'row' }}
/>

// Same as:
<Box
  p={{ base: undefined, md: 16, lg: 24 }}
  br={{ base: undefined, md: 8, lg: 12 }}
  flexDirection={{ base: undefined, lg: 'row' }}
/>
When the same property is supplied through both a responsive object and a $-prefixed group for the same breakpoint, the $-prefixed value wins.

▸ $-prefixed syntax — Use $breakpoint groups to co-locate props for the same breakpoint. They are concise alternatives to responsive objects. When both forms set the same property, the $-group takes precedence.

// $md value wins over the responsive object's md value
<Box
  p={{ base: 8, md: 12 }}  // md = 12 from responsive object
  $md={{ p: 16 }}          // md = 16 from $-group — this wins
/>
// Result at md: p = 16

All components accept responsive props

Every component in @stareezy-ui/components extends BoxLayoutProps, so responsive layout props work on all of them — not just Box.

import { Button, Input, Card, Badge } from '@stareezy-ui/components'

<Button
  p={{ base: 8, md: 12 }}
  w={{ base: '100%', md: 'auto' }}
  $lg={{ px: 20, py: 10 }}
/>

<Input
  w={{ base: '100%', md: 360 }}
  mb={{ base: 8, lg: 0 }}
/>

<Card
  p={{ base: 12, md: 20, lg: 28 }}
  $md={{ flexDirection: 'row' }}
/>

<Badge
  px={{ base: 8, md: 12 }}
  py={{ base: 4, md: 6 }}
/>

Default breakpoints

If you do not augment SzrCustomConfig with a media configuration, the following defaults apply:

Keymin-widthTypical target
base0pxAll screens (no media query)
sm480pxLarge phones
md768pxTablets
lg1024pxLaptops
xl1280pxDesktops
2xl1536pxWide screens