Responsive Item
The ResponsiveItem
component can be used to make images, videos, iframes, or
other media elements responsive within a relative container with built-in
support for forcing specific aspect ratios when the item's size is unknown.
See the objectFit class name utility function for a simpler implementation.
Simple Example
This example will show how to create responsive images by wrapping the
<img>
element in the ResponsiveItem
. The default behavior
will be to respect the <img>
dimensions but scale them down into the
container's width.
Try resizing the browser or updating the columns
constant in the next
demo to see how it works.
import { Box } from "@react-md/core/box/Box";
import { type BoxOptions } from "@react-md/core/box/styles";
import { Card } from "@react-md/core/card/Card";
import { ResponsiveItem } from "@react-md/core/responsive-item/ResponsiveItem";
import { type ReactElement } from "react";
export default function SimpleExample(): ReactElement {
return (
<Box align="stretch" grid fullWidth gridColumns={columns}>
<Card align="center" justify="center">
<ResponsiveItem>
<img src="https://picsum.photos/200/300?image=30" alt="" />
</ResponsiveItem>
</Card>
<Card align="center" justify="center">
<ResponsiveItem>
<img src="https://picsum.photos/300/200?image=3" alt="" />
</ResponsiveItem>
</Card>
<Card align="center" justify="center">
<ResponsiveItem>
<img src="https://picsum.photos/300?image=1008" alt="" />
</ResponsiveItem>
</Card>
<Card align="center" justify="center">
<ResponsiveItem>
<img src="https://picsum.photos/100/110?image=233" alt="" />
</ResponsiveItem>
</Card>
</Box>
);
}
// eslint-disable-next-line prefer-const
let columns: BoxOptions["gridColumns"] = undefined;
// columns = "fit";
// columns = "fill";
// columns = 2;
Force Aspect Ratio
When dealing with unknown content, the aspect ratio can be forced using
the aspectRatio
prop. The default aspect ratios are:
16-9
, 4-3
, and 1-1
.
import { Box } from "@react-md/core/box/Box";
import { Card } from "@react-md/core/card/Card";
import { ResponsiveItem } from "@react-md/core/responsive-item/ResponsiveItem";
import { type ReactElement } from "react";
export default function ForceAspectRatio(): ReactElement {
return (
<Box grid fullWidth>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/400/300?image=3" alt="" />
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="4-3">
<img src="https://picsum.photos/400/300?image=3" alt="" />
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="1-1">
<img src="https://picsum.photos/300/400?image=3" alt="" />
</ResponsiveItem>
</Card>
</Box>
);
}
YouTube IFrame Example
When a YouTube video should be rendered in an iframe, either the height
and
width
need to be provided to the iframe
or an aspect ratio must be set on
the ResponsiveItem
to work correctly.
import { Card } from "@react-md/core/card/Card";
import { ResponsiveItem } from "@react-md/core/responsive-item/ResponsiveItem";
import { type ReactElement } from "react";
export default function YouTubeIFrame(): ReactElement {
return (
<Card fullWidth>
<ResponsiveItem aspectRatio="16-9">
<iframe
src="https://www.youtube.com/embed/kyAn3fSs8_A"
allowFullScreen
title="Archer - Highway To The Dangerzone"
style={{ border: 0 }}
/>
</ResponsiveItem>
</Card>
);
}
Configuring Allowed Aspect Ratios
The generated aspect ratios are configured by the
core.$responsive-item-aspect-ratios Sass variable which is a map of
x-y: x y
.
Responsive Item Overlay Example
It can sometimes be useful to add an overlay above the responsive item to cover
it with a title, description, or other information. Use the ResponsiveItemOverlay
component to add this overlayh within a ResponsiveItem
.
import { Box } from "@react-md/core/box/Box";
import { box } from "@react-md/core/box/styles";
import { button } from "@react-md/core/button/styles";
import { Card } from "@react-md/core/card/Card";
import { ResponsiveItem } from "@react-md/core/responsive-item/ResponsiveItem";
import { ResponsiveItemOverlay } from "@react-md/core/responsive-item/ResponsiveItemOverlay";
import { Typography } from "@react-md/core/typography/Typography";
import InfoOutlineIcon from "@react-md/material-icons/InfoOutlineIcon";
import { type ReactElement } from "react";
export default function ResponsiveItemOverlayExample(): ReactElement {
return (
<Box grid fullWidth>
<Card>
<ResponsiveItem>
<img
src="https://picsum.photos/800/800?image=432"
alt="green trees, grass, and lake at sunrise"
/>
<ResponsiveItemOverlay
className={box({ justify: "space-between", disablePadding: true })}
>
<Typography type="headline-5" margin="none">
Photo by: Michael Hull
</Typography>
<a
aria-label="Unsplash photo source"
rel="noreferrer"
href="https://unsplash.com/photos/photo-of-green-trees-grass-and-lake-at-sunrise-vuWB5mGu5wE"
target="_blank"
className={button({ buttonType: "icon" })}
>
<InfoOutlineIcon />
</a>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
</Box>
);
}
Overlay Positions
The ResponsiveItemOverlay
supports the following positions:
top
right
bottom
(default)left
middle
- vertically centeredcenter
- horizontally centeredabsolute-center
- horizontally and vertically centered
import { Box } from "@react-md/core/box/Box";
import { Card } from "@react-md/core/card/Card";
import { ResponsiveItem } from "@react-md/core/responsive-item/ResponsiveItem";
import { ResponsiveItemOverlay } from "@react-md/core/responsive-item/ResponsiveItemOverlay";
import { Typography } from "@react-md/core/typography/Typography";
import { type ReactElement } from "react";
export default function OverlayPositions(): ReactElement {
return (
<Box grid fullWidth gridColumns={1}>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="top">
<Typography type="headline-5" margin="none">
Top
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="right">
<Typography type="headline-5" margin="none">
Right
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="bottom">
<Typography type="headline-5" margin="none">
Bottom (default)
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="left">
<Typography type="headline-5" margin="none">
Left
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="middle">
<Typography type="headline-5" margin="none" textAlign="center">
Middle
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="center">
<Typography type="headline-5" margin="none" textAlign="center">
Center
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
<Card>
<ResponsiveItem aspectRatio="16-9">
<img src="https://picsum.photos/600/600?image=404" alt="" />
<ResponsiveItemOverlay position="absolute-center">
<Typography type="headline-5" margin="none" textAlign="center">
Absolute Center
</Typography>
</ResponsiveItemOverlay>
</ResponsiveItem>
</Card>
</Box>
);
}
Customizing Styles
The global overlay styles can be configured by changing the following sass variables:
- core.$responsive-item-overlay-background-color
- core.$responsive-item-overlay-color
- core.$responsive-item-overlay-z-index
- core.$responsive-item-overlay-padding
- core.$responsive-item-overlay-horizontal-width
Otherwise, custom styles can be provided using the className
prop like normal.