Design Tokens

Border Radiuses

Create and manage border radius design tokens with CSS variables for consistent rounded corners and curved edges across your application.

Overview

The border radius composable helps you create consistent rounded corner systems with minimal code. It generates border-radius variables that can be easily referenced throughout your application, enabling flexible theming and consistent visual styling for your components.

Why use border radius composables?

Border radius composables help you:

  • Maintain visual consistency: Define corner radius values once and use them throughout your application.
  • Enable flexible theming: Override border radius variables to instantly update component styling across your application.
  • Simplify component styling: Reference semantic border radius names instead of repeating pixel values.
  • Create cohesive design systems: Establish a standard set of border radius values that work harmoniously together.
  • Support theme variations: Easily switch between sharp, rounded, or pill-shaped corners across your entire design system.

useBorderRadius

The useBorderRadius() function creates a set of border radius variables from a simple object of radius value definitions.

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useBorderRadius } from '@styleframe/theme';

const s = styleframe();

const {
    borderRadius,
    borderRadiusNone,
    borderRadiusSm,
    borderRadiusMd,
    borderRadiusLg,
    borderRadiusXl,
    borderRadiusFull,
} = useBorderRadius(s, {
    none: '0',
    sm: '0.25rem',
    md: '0.375rem',
    lg: '0.5rem',
    xl: '0.75rem',
    full: '9999px',
    default: '@md',
} as const);

export default s;

Each key in the object becomes a border radius variable with the prefix border-radius--, and the export name is automatically converted to camelCase (e.g., smborderRadiusSm, mdborderRadiusMd).

Pro tip: Use the default key for your most common border radius. It will create a variable named --border-radius without any suffix, making it the natural choice for standard rounded corners throughout your application.

Integration with useMultiplier

The real power of useBorderRadius comes when combined with useMultiplier() and modular scales. This allows you to create mathematically harmonious border radius systems that maintain consistent proportions.

Create a border radius scale based on a modular scale ratio:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useScale, useScalePowers, useMultiplier, useBorderRadius, defaultScaleValues } from '@styleframe/theme';

const s = styleframe();

// Use the Minor Third scale (1.2) for balanced progression
const { scale } = useScale(s, { ...defaultScaleValues, default: '@minor-third' });

// Define base border radius
const { borderRadius } = useBorderRadius(s, { default: '0.25rem' });

// Create scale powers
const scalePowers = useScalePowers(s, scale);

// Generate border radius variables automatically
const {
    borderRadiusXs,
    borderRadiusSm,
    borderRadiusMd,
    borderRadiusLg,
    borderRadiusXl,
    borderRadius2xl,
} = useMultiplier(s, borderRadius, {
    xs: scalePowers[-2],   // ~0.17rem
    sm: scalePowers[-1],   // ~0.21rem
    md: scalePowers[0],    // 0.25rem (base)
    lg: scalePowers[1],    // ~0.30rem
    xl: scalePowers[2],    // ~0.36rem
    '2xl': scalePowers[3], // ~0.43rem
});

export default s;

The useMultiplier() function multiplies your base border radius by the scale powers, creating a harmonious progression of corner radius values. This ensures consistent proportional relationships throughout your design system.

Read more about design scales and take advantage of the flexibility they offer.

Pro tip: Using useMultiplier() with scales means you can change your entire border radius system's proportions by simply adjusting the scale ratio. Try different scales like Major Third (1.25) for more dramatic differences or Major Second (1.125) for subtle variations.

Creating Custom Border Radius Variables

You can define your own custom border radius scale to match your design system's needs:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useBorderRadius } from '@styleframe/theme';

const s = styleframe();

const {
    borderRadius,
    borderRadiusSquare,
    borderRadiusRounded,
    borderRadiusPill,
} = useBorderRadius(s, {
    default: '0.5rem',
    square: '0',
    rounded: '0.5rem',
    pill: '9999px',
} as const);

export default s;

Referencing Other Border Radius Values

Use the @ prefix to reference another border radius value within your definitions:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useBorderRadius } from '@styleframe/theme';

const s = styleframe();

const {
    borderRadius,
    borderRadiusNone,
    borderRadiusSm,
    borderRadiusMd,
    borderRadiusLg,
} = useBorderRadius(s, {
    none: '0',
    sm: '0.25rem',
    md: '0.5rem',
    lg: '0.75rem',
    default: '@md',  // References the 'md' value
} as const);

export default s;

Using Border Radius Variables

Once created, border radius variables can be used anywhere in your styles:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useBorderRadius } from '@styleframe/theme';

const s = styleframe();
const { ref, selector } = s;

const { borderRadius, borderRadiusSm, borderRadiusLg, borderRadiusFull } = useBorderRadius(s, {
    default: '0.375rem',
    sm: '0.25rem',
    lg: '0.5rem',
    full: '9999px',
} as const);

selector('.card', {
    borderRadius: ref(borderRadius),
});

selector('.button', {
    borderRadius: ref(borderRadiusSm),
});

selector('.modal', {
    borderRadius: ref(borderRadiusLg),
});

selector('.avatar', {
    borderRadius: ref(borderRadiusFull),
});

export default s;

Examples

Scale-Based Border Radius System

Create a complete border radius system using modular scales:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useScale, useScalePowers, useMultiplier, useBorderRadius, defaultScaleValues } from '@styleframe/theme';

const s = styleframe();
const { ref, selector } = s;

// Use Minor Third scale (1.2) for balanced corner progressions
const { scale } = useScale(s, { ...defaultScaleValues, default: '@minor-third' });

// Define base border radius
const { borderRadius } = useBorderRadius(s, { default: '0.375rem' });

// Create scale powers
const scalePowers = useScalePowers(s, scale, [-2, -1, 0, 1, 2, 3, 4]);

// Generate border radius scale
const {
    borderRadiusXs,
    borderRadiusSm,
    borderRadiusMd,
    borderRadiusLg,
    borderRadiusXl,
    borderRadius2xl,
    borderRadius3xl,
} = useMultiplier(s, borderRadius, {
    xs: scalePowers[-2],   // ~0.26rem - badges, small buttons
    sm: scalePowers[-1],   // ~0.31rem - buttons, inputs
    md: scalePowers[0],    // 0.375rem (base) - cards, standard surfaces
    lg: scalePowers[1],    // ~0.45rem - panels, large cards
    xl: scalePowers[2],    // ~0.54rem - modals, dialogs
    '2xl': scalePowers[3], // ~0.65rem - hero sections
    '3xl': scalePowers[4], // ~0.78rem - large surfaces
});

// Apply to components based on size
selector('.badge', {
    borderRadius: ref(borderRadiusXs),
    padding: '0.125rem 0.375rem',
    fontSize: '0.75rem',
});

selector('.btn', {
    borderRadius: ref(borderRadiusSm),
    padding: '0.5rem 1rem',
});

selector('.card', {
    borderRadius: ref(borderRadiusMd),
    padding: '1.5rem',
});

selector('.modal', {
    borderRadius: ref(borderRadiusLg),
    padding: '2rem',
});

selector('.hero', {
    borderRadius: ref(borderRadiusXl),
    padding: '3rem',
});

export default s;

Component-Specific Border Radius System

Create a border radius system tailored for specific component types:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useBorderRadius } from '@styleframe/theme';

const s = styleframe();
const { ref, selector } = s;

const {
    borderRadius,
    borderRadiusButton,
    borderRadiusCard,
    borderRadiusInput,
    borderRadiusModal,
    borderRadiusBadge,
    borderRadiusAvatar,
} = useBorderRadius(s, {
    default: '0.375rem',
    button: '0.375rem',
    card: '0.5rem',
    input: '0.25rem',
    modal: '0.75rem',
    badge: '0.25rem',
    avatar: '9999px',
} as const);

selector('.btn', {
    borderRadius: ref(borderRadiusButton),
    padding: '0.5rem 1rem',
});

selector('.card', {
    borderRadius: ref(borderRadiusCard),
    padding: '1.5rem',
});

selector('.input', {
    borderRadius: ref(borderRadiusInput),
    padding: '0.5rem',
    border: '1px solid #d1d5db',
});

selector('.modal', {
    borderRadius: ref(borderRadiusModal),
    padding: '2rem',
});

selector('.badge', {
    borderRadius: ref(borderRadiusBadge),
    padding: '0.25rem 0.5rem',
    fontSize: '0.75rem',
});

selector('.avatar', {
    borderRadius: ref(borderRadiusAvatar),
    width: '2.5rem',
    height: '2.5rem',
});

export default s;

Best Practices

  • Start with a small scale: 3-5 border radius values are usually sufficient.
  • Use semantic names: Choose names that describe the size or use case (e.g., sm, md, lg) rather than specific pixel values.
  • Integrate with scales: Combine useBorderRadius() with useMultiplier() for mathematically harmonious border radius systems that scale proportionally.
  • Maintain proportional relationships: Larger components should generally have larger border radius values to maintain visual harmony.
  • Coordinate with spacing: Consider using the same scale ratio for border radius as you use for spacing to maintain visual consistency across your design system.
  • Consider your brand: Sharp corners (0) feel modern and technical, while rounded corners feel friendly and approachable. Very large radii create a playful, organic feel.
  • Use full for circular elements: Set border radius to 9999px or 50% for perfectly circular avatars, badges, and icons.
  • Be consistent with component types: All buttons should use the same radius, all cards should use the same radius, etc.
  • Test with borders: Border radius is most noticeable on elements with borders or backgrounds—test your values in context.
  • Mind the container size: Very large border radius values can look awkward on small elements. The radius should never exceed half the element's smallest dimension for a true rounded corner effect.
Good to know: We use as const to ensure the object is treated as a constant type. This helps TypeScript infer the return type of the composables and provides better type safety and autocomplete support.

FAQ