Utilities for working with responsive breakpoints, media queries, and responsive prop values. These utilities support both object and array notation for responsive values and provide breakpoint analysis capabilities for building responsive UI systems.
Core utilities for working with CSS units and media queries.
/**
* Converts unitless values to px strings
* @param value - Number, string, or null value to convert
* @returns String with px unit or null
*/
function px(value: number | string | null): string | null;
/**
* Creates CSS media query string from min and max values
* @param min - Minimum breakpoint value
* @param max - Maximum breakpoint value (optional)
* @returns CSS media query string
*/
function toMediaQueryString(min: string | null, max?: string): string;Usage Examples:
import { px, toMediaQueryString } from "@chakra-ui/utils";
// Unit conversion
const spacing = {
sm: px(8), // "8px"
md: px(16), // "16px"
lg: px(24), // "24px"
xl: px("2rem") // "2rem"
};
// Media query generation
const breakpoints = {
sm: "768px",
md: "1024px",
lg: "1200px"
};
const mediaQueries = {
mobile: toMediaQueryString(null, breakpoints.sm), // "@media (max-width: 768px)"
tablet: toMediaQueryString(breakpoints.sm, breakpoints.md), // "@media (min-width: 768px) and (max-width: 1024px)"
desktop: toMediaQueryString(breakpoints.md), // "@media (min-width: 1024px)"
};
// CSS-in-JS usage
const styles = {
container: {
padding: px(16),
[mediaQueries.mobile]: {
padding: px(8)
},
[mediaQueries.desktop]: {
padding: px(32)
}
}
};Advanced breakpoint system analysis and utility generation.
/**
* Analyzes breakpoint configuration and provides utility functions
* @param breakpoints - Object containing breakpoint definitions
* @returns Object with breakpoint utilities or null if invalid
*/
function analyzeBreakpoints(breakpoints: Record<string, any>): AnalyzeBreakpointsReturn | null;
interface AnalyzeBreakpointsReturn {
keys: string[];
normalized: string[];
asObject: Record<string, string>;
asArray: string[];
details: BreakpointDetail[];
media: string[];
}
interface BreakpointDetail {
breakpoint: string;
maxWidth: string | undefined;
minWidth: string;
maxWidthValue: number | undefined;
minWidthValue: number;
}Usage Examples:
import { analyzeBreakpoints } from "@chakra-ui/utils";
// Analyze custom breakpoints
const customBreakpoints = {
mobile: "320px",
tablet: "768px",
desktop: "1024px",
wide: "1440px"
};
const analysis = analyzeBreakpoints(customBreakpoints);
if (analysis) {
console.log("Breakpoint keys:", analysis.keys); // ["mobile", "tablet", "desktop", "wide"]
console.log("Media queries:", analysis.media); // ["@media (min-width: 320px)", ...]
console.log("Breakpoint details:", analysis.details); // Detailed breakpoint information
// Use in styled components
const StyledComponent = styled.div`
${analysis.media[0]} {
font-size: 14px;
}
${analysis.media[1]} {
font-size: 16px;
}
`;
}
// Theme integration
function createTheme(breakpoints: Record<string, string>) {
const analysis = analyzeBreakpoints(breakpoints);
return {
breakpoints: analysis?.asObject || {},
mediaQueries: analysis?.media || [],
space: analysis?.normalized.map(bp => px(parseInt(bp))) || []
};
}Default breakpoints and utilities for handling responsive prop values.
/**
* Default breakpoint names used throughout Chakra UI
*/
const breakpoints: ["base", "sm", "md", "lg", "xl", "2xl"];
/**
* Maps responsive prop values using a mapper function
* @param prop - Responsive prop value (object, array, or single value)
* @param mapper - Function to transform each value
* @returns Transformed responsive value
*/
function mapResponsive(prop: any, mapper: (val: any) => any): any;
/**
* Converts responsive object notation to array notation
* @param obj - Responsive object with breakpoint keys
* @param bps - Optional breakpoint names array
* @returns Array of responsive values
*/
function objectToArrayNotation(obj: Record<string, any>, bps?: string[]): any[];
/**
* Converts responsive array notation to object notation
* @param values - Array of responsive values
* @param bps - Optional breakpoint names array
* @returns Object with breakpoint keys
*/
function arrayToObjectNotation(values: any[], bps?: string[]): Record<string, any>;
/**
* Checks if an object looks like a responsive object
* @param obj - Object to check
* @param bps - Optional breakpoint names array
* @returns true if object appears to be responsive
*/
function isResponsiveObjectLike(obj: Record<string, any>, bps?: string[]): boolean;
/**
* Checks if a breakpoint key is custom (not in default set)
* @param v - Breakpoint key to check
* @returns true if breakpoint is custom
*/
function isCustomBreakpoint(v: string): boolean;Usage Examples:
import {
breakpoints,
mapResponsive,
objectToArrayNotation,
arrayToObjectNotation,
isResponsiveObjectLike
} from "@chakra-ui/utils";
// Working with responsive props
interface BoxProps {
padding?: ResponsiveValue<string | number>;
margin?: ResponsiveValue<string | number>;
}
type ResponsiveValue<T> = T | T[] | Record<string, T>;
function Box({ padding, margin }: BoxProps) {
// Transform responsive padding values
const responsivePadding = mapResponsive(padding, (value) => {
return typeof value === "number" ? `${value * 4}px` : value;
});
// Convert between notations
const paddingArray = Array.isArray(padding)
? padding
: isResponsiveObjectLike(padding)
? objectToArrayNotation(padding, breakpoints)
: [padding];
const paddingObject = arrayToObjectNotation(paddingArray, breakpoints);
return (
<div
style={{
padding: responsivePadding,
margin: mapResponsive(margin, value => px(value))
}}
/>
);
}
// Usage examples
const responsiveProps = {
// Object notation
padding: { base: "4px", md: "8px", lg: "16px" },
// Array notation
margin: ["2px", "4px", "8px", "16px"],
// Single value
border: "1px solid"
};
// Transform responsive spacing system
function createSpacingSystem(baseUnit: number) {
const scale = [0, 1, 2, 4, 8, 16, 32, 64];
return mapResponsive(scale, (value) => `${value * baseUnit}px`);
}
// Responsive typography
const responsiveText = {
fontSize: { base: "14px", md: "16px", lg: "18px" },
lineHeight: { base: 1.4, md: 1.5, lg: 1.6 }
};
const processedText = {
fontSize: mapResponsive(responsiveText.fontSize, px),
lineHeight: mapResponsive(responsiveText.lineHeight, (value) => value)
};Common patterns for building responsive components.
import {
mapResponsive,
analyzeBreakpoints,
isResponsiveObjectLike
} from "@chakra-ui/utils";
// Responsive Grid component
interface GridProps {
columns?: ResponsiveValue<number>;
gap?: ResponsiveValue<string | number>;
children: React.ReactNode;
}
function ResponsiveGrid({ columns = 1, gap = "1rem", children }: GridProps) {
const gridColumns = mapResponsive(columns, (cols) => `repeat(${cols}, 1fr)`);
const gridGap = mapResponsive(gap, (g) => px(g));
return (
<div
style={{
display: "grid",
gridTemplateColumns: gridColumns,
gap: gridGap
}}
>
{children}
</div>
);
}
// Usage
<ResponsiveGrid
columns={{ base: 1, md: 2, lg: 3 }}
gap={["8px", "16px", "24px"]}
>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</ResponsiveGrid>
// Responsive Text component
interface TextProps {
size?: ResponsiveValue<"sm" | "md" | "lg" | "xl">;
children: React.ReactNode;
}
const textSizes = {
sm: { fontSize: "14px", lineHeight: "1.4" },
md: { fontSize: "16px", lineHeight: "1.5" },
lg: { fontSize: "18px", lineHeight: "1.6" },
xl: { fontSize: "24px", lineHeight: "1.4" }
};
function ResponsiveText({ size = "md", children }: TextProps) {
const styles = mapResponsive(size, (s) => textSizes[s]);
return <p style={styles}>{children}</p>;
}
// Usage
<ResponsiveText size={{ base: "sm", md: "md", lg: "lg" }}>
This text scales with breakpoints
</ResponsiveText>
// Custom breakpoint system
const customBreakpoints = {
xs: "320px",
sm: "640px",
md: "768px",
lg: "1024px",
xl: "1280px"
};
const breakpointSystem = analyzeBreakpoints(customBreakpoints);
function useBreakpoints() {
const [currentBreakpoint, setCurrentBreakpoint] = React.useState("xs");
React.useEffect(() => {
if (!breakpointSystem) return;
const mediaQueries = breakpointSystem.details.map(detail => ({
query: window.matchMedia(detail.minWidth ? `(min-width: ${detail.minWidth})` : "all"),
breakpoint: detail.breakpoint
}));
const updateBreakpoint = () => {
const matched = mediaQueries
.reverse()
.find(mq => mq.query.matches);
if (matched) {
setCurrentBreakpoint(matched.breakpoint);
}
};
mediaQueries.forEach(mq => mq.query.addEventListener("change", updateBreakpoint));
updateBreakpoint();
return () => {
mediaQueries.forEach(mq => mq.query.removeEventListener("change", updateBreakpoint));
};
}, []);
return currentBreakpoint;
}