AspectRatio
The AspectRatio component ensures that its children maintain a specific width-to-height ratio, making it ideal for videos, images, or placeholders that need to be consistently sized across devices.
Preview
- Preview
- Code
import { AspectRatio } from '@ignix-ui/aspectratio';
function MyComponent() {
return (
<AspectRatio ratio="16:9" maxWidth="400px">
<img src="https://thumbs.wbm.im/pw/medium/859204cf5b71808ed4c6bd19d95974c6.jpg" alt="Demo Image" />
</AspectRatio>
);
}
Installation
- CLI
- manual
ignix add component aspectratio
import { cn } from '../../../utils/cn';
import * as React from 'react';
export interface AspectRatioProps extends React.HTMLAttributes<HTMLDivElement> {
ratio?: '1:1' | '4:3' | '16:9' | '21:9' | string;
/**
* The maximum width of the container.
* - Accepts a string (e.g., '50%', '30rem', '400px')
* - Or a number (auto-converted to 'px')
*/
maxWidth?: string | number;
children: React.ReactNode;
}
const parseRatio = (ratio: string) => {
const [w, h] = ratio.split(':').map(Number);
return w && h ? { w, h } : { w: 1, h: 1 };
};
const AspectRatio = React.forwardRef<HTMLDivElement, AspectRatioProps>(
({ ratio = '1:1', maxWidth, children, className, style, ...props }, ref) => {
const { w, h } = parseRatio(ratio);
const isAspectRatioSupported =
typeof CSS !== 'undefined' && CSS.supports('aspect-ratio', '1/1');
const computedWidth =
typeof maxWidth === 'number' ? `${maxWidth}px` : (maxWidth ?? '100%');
const containerStyle: React.CSSProperties = {
position: 'relative',
width: computedWidth,
maxWidth: '100%',
aspectRatio: `${w} / ${h}`,
...style,
};
if (isAspectRatioSupported) {
containerStyle.aspectRatio = `${w} / ${h}`;
} else {
containerStyle.position = 'relative';
containerStyle.paddingBottom = `${(h / w) * 100}%`;
}
const contentStyle: React.CSSProperties = isAspectRatioSupported
? { width: '100%', height: '100%' }
: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
};
const enhancedChildren = React.Children.map(children, (child) => {
if (
React.isValidElement(child) &&
typeof child.type === 'string' &&
child.type === 'img'
) {
const imgElement = child as React.ReactElement<
React.ImgHTMLAttributes<HTMLImageElement>
>;
return React.cloneElement(imgElement, {
className: cn(
imgElement.props.className,
'object-cover w-full h-full'
),
});
}
return child;
});
return (
<div
ref={ref}
className={cn('aspect-ratio-container', className)}
style={containerStyle}
{...props}
>
{isAspectRatioSupported ? (
enhancedChildren
) : (
<div style={contentStyle}>{enhancedChildren}</div>
)}
</div>
);
}
);
AspectRatio.displayName = 'AspectRatio';
export { AspectRatio };
Usage
Import the component:
import { AspectRatio } from '@ignix-ui/aspectratio';
Basic Usage
function BasicAspectRatio() {
return (
<AspectRatio ratio="4:3" maxWidth="500px">
<img src="https://thumbs.wbm.im/pw/medium/859204cf5b71808ed4c6bd19d95974c6.jpg" alt="Demo Image" />
</AspectRatio>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
ratio | "1:1" | "4:3" | "16:9" | "21:9" | string | "1:1" | The width-to-height ratio. Accepts any custom "W:H" string |
maxWidth | string | number | - | Maximum width of the container. (e.g. "50%", "30rem", "400px"). Numbers are auto-converted to px |
children | React.ReactNode | required | Content rendered inside the ratio container. Direct <img> children automatically receive object-cover w-full h-full |