Border Radiuses
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.
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;
:root {
--border-radius--none: 0;
--border-radius--sm: 0.25rem;
--border-radius--md: 0.375rem;
--border-radius--lg: 0.5rem;
--border-radius--xl: 0.75rem;
--border-radius--full: 9999px;
--border-radius: var(--border-radius--md);
}
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., sm → borderRadiusSm, md → borderRadiusMd).
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:
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;
:root {
--scale--minor-third: 1.2;
--scale: var(--scale--minor-third);
--border-radius: 0.25rem;
--border-radius--xs: calc(var(--border-radius) * 1 / var(--scale) / var(--scale));
--border-radius--sm: calc(var(--border-radius) * 1 / var(--scale));
--border-radius--md: calc(var(--border-radius) * 1);
--border-radius--lg: calc(var(--border-radius) * var(--scale));
--border-radius--xl: calc(var(--border-radius) * var(--scale) * var(--scale));
--border-radius--2xl: calc(var(--border-radius) * var(--scale) * var(--scale) * var(--scale));
}
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.
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:
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;
:root {
--border-radius--square: 0;
--border-radius--rounded: 0.5rem;
--border-radius--pill: 9999px;
--border-radius: 0.5rem;
}
Referencing Other Border Radius Values
Use the @ prefix to reference another border radius value within your definitions:
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;
:root {
--border-radius--none: 0;
--border-radius--sm: 0.25rem;
--border-radius--md: 0.5rem;
--border-radius--lg: 0.75rem;
--border-radius: var(--border-radius--md);
}
Using Border Radius Variables
Once created, border radius variables can be used anywhere in your styles:
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;
:root {
--border-radius: 0.375rem;
--border-radius--sm: 0.25rem;
--border-radius--lg: 0.5rem;
--border-radius--full: 9999px;
}
.card {
border-radius: var(--border-radius);
}
.button {
border-radius: var(--border-radius--sm);
}
.modal {
border-radius: var(--border-radius--lg);
}
.avatar {
border-radius: var(--border-radius--full);
}
Examples
Scale-Based Border Radius System
Create a complete border radius system using modular scales:
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;
:root {
--scale--minor-third: 1.2;
--scale: var(--scale--minor-third);
--border-radius: 0.375rem;
--border-radius--xs: calc(var(--border-radius) * var(--scale-power---2));
--border-radius--sm: calc(var(--border-radius) * var(--scale-power---1));
--border-radius--md: calc(var(--border-radius) * var(--scale-power--0));
--border-radius--lg: calc(var(--border-radius) * var(--scale-power--1));
--border-radius--xl: calc(var(--border-radius) * var(--scale-power--2));
--border-radius--2xl: calc(var(--border-radius) * var(--scale-power--3));
--border-radius--3xl: calc(var(--border-radius) * var(--scale-power--4));
}
.badge {
border-radius: var(--border-radius--xs);
padding: 0.125rem 0.375rem;
font-size: 0.75rem;
}
.btn {
border-radius: var(--border-radius--sm);
padding: 0.5rem 1rem;
}
.card {
border-radius: var(--border-radius--md);
padding: 1.5rem;
}
.modal {
border-radius: var(--border-radius--lg);
padding: 2rem;
}
.hero {
border-radius: var(--border-radius--xl);
padding: 3rem;
}
Component-Specific Border Radius System
Create a border radius system tailored for specific component types:
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;
:root {
--border-radius: 0.375rem;
--border-radius--button: 0.375rem;
--border-radius--card: 0.5rem;
--border-radius--input: 0.25rem;
--border-radius--modal: 0.75rem;
--border-radius--badge: 0.25rem;
--border-radius--avatar: 9999px;
}
.btn {
border-radius: var(--border-radius--button);
padding: 0.5rem 1rem;
}
.card {
border-radius: var(--border-radius--card);
padding: 1.5rem;
}
.input {
border-radius: var(--border-radius--input);
padding: 0.5rem;
border: 1px solid #d1d5db;
}
.modal {
border-radius: var(--border-radius--modal);
padding: 2rem;
}
.badge {
border-radius: var(--border-radius--badge);
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}
.avatar {
border-radius: var(--border-radius--avatar);
width: 2.5rem;
height: 2.5rem;
}
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()withuseMultiplier()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
fullfor circular elements: Set border radius to9999pxor50%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.
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
rem units makes border radius scale with the user's font size preferences, which can be beneficial for accessibility. However, px units provide more predictable results across different font size settings. For most applications, rem is recommended for consistency with your spacing and typography systems, but px is perfectly acceptable if you prefer absolute control.50% or 9999px works. The 50% approach is more semantic, but 9999px is a common convention that ensures the element appears circular regardless of its size. Both approaches are valid—choose what feels more intuitive to your team.useBorderRadius() creates border radius variables from explicit values you provide. useMultiplier() automatically generates border radius variables by multiplying a base border radius variable by scale powers. Use useBorderRadius() for manual control or useMultiplier() for systematic, scale-based corner radius progressions.transition property to smoothly animate between different border radius values on hover or other state changes: transition: 'border-radius 0.2s ease'.css template function or setting borderTopLeftRadius, borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius individually.