Skip to content

Tiles

Edit on GitHub

Interactive navigation elements with text-only or media-and-text layouts for linking to content.

@volvo-cars/css v2.5.1

Tiles are semantic links or buttons. Use Cards when the content container itself should not be interactive.

The text tile is a compact interactive element with an optional icon at the top and a body label anchored to the bottom. The icon is a direct child of the tile, not a slotted element.

When the icon is omitted, space is reserved at the top and the body label stays anchored to the bottom.

Show codeHide code
import { Icon } from '@volvo-cars/react-icons';
export function TextTile() {
return (
<div
className="grid-cols-2 gap-x-gutter gap-y-24"
style={{ height: '200px' }}
>
<a href="#top" className="text-tile">
<Icon icon="charging-battery" size={24} />
<span slot="body">Charging</span>
</a>
<a href="#top" className="text-tile">
<span slot="body">Without icon</span>
</a>
</div>
);
}

This component uses slots to give content built-in styling.

  • Icon – Direct child element (not slotted)
  • slot="body" – Label text
Show codeHide code
<a class="text-tile" href="#" style="height: 200px">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
>
<path stroke="currentColor" stroke-width="1.5" d="M12 3v18M3 12h18" />
</svg>
<code slot="body">body</code>
</a>

Wrap tiles in <li> elements inside a <ul> for semantic grouping. Give the container a fixed height so tiles share consistent dimensions.

The media tile pairs an image with a body label. The media slot defaults to a 4 / 3 aspect ratio. Images hover-zoom on interaction.

Show codeHide code
<a href="#" class="media-tile" style="max-width: 360px">
<div slot="media">
<img class="img" src="/images/cars/card/es90.avif" alt="" />
</div>
<span slot="body">Explore the Volvo ES90</span>
</a>

This component uses slots to give content built-in styling.

  • slot="media" – Image container
  • slot="body" – Label text
Show codeHide code
<a class="media-tile" href="#" style="max-width: 280px">
<div
slot="media"
class="bg-feedback-gray flex items-center justify-center h-full"
>
<code>media</code>
</div>
<code slot="body">body</code>
</a>

The media slot requires a wrapping <div>: images are absolutely positioned inside it for the hover zoom effect.

Add flex-row items-center gap-16 to arrange the media beside the label. Set a fixed width on the media slot to control its size. The aspect ratio determines the height.

Arrange media tiles as list items in a CSS grid, using the same semantic grouping as text tiles.

  • Always use <a> for navigation or <button> for actions. Tiles must be interactive elements
  • Provide descriptive alt text for images, or use alt="" for decorative images when the body label provides sufficient context
  • Add aria-hidden="true" to decorative icons that repeat the body label’s meaning
  • In grid layouts, wrap tiles in <li> elements inside a <ul> for semantic list structure
  • The body label is styled with an underline to signal interactivity without relying on color alone
ClassDescription
text-tileInteractive tile with optional icon and bottom-anchored label. Secondary background.
media-tileInteractive tile with image (4:3 cover) and label. Image zooms on hover.