picture_tag helper in Rails

Rails recently introduced a new helper - picture_tag. This adds a tag helper picture_tag which generates a <picture> tag with <source> and <img> tags.

Why picture tag?

As we build modern web applications, we need to support different devices with different screen sizes and resolutions. We also need to support different image formats like webp and avif for better performance.

Although most applications still rely on jpeg or png images, which in Rails, can currently be served by the image_tag easily.

Responsive applications serving these images to different devices and browsers, generally use srcset and sizes attributes of the <img> tag.

Here’s a simple example making use of srcset attribute to provide different images for different screen sizes.

<div class="box">
    srcset="/en-us/web/html/element/img/clock-demo-400px.png 2x" />

This still leaves us slow loading of images sometimes, as we try to load a larger images with better resolution. As well as the images may be cropped as we move across devices, requiring portrait mode or landscape mode images and so on.

The picture tag helps us solve some of these problems and provides a better way to serve images. It can consists of a series of source tags with different srcset and media attributes, and a fallback img tag if none of the source tags match.

    <source srcset="/car-240-200.jpg" media="(orientation: portrait)">
    <img src="/small-car-298-332.jpg" alt="">

Art Direction

The problem being solved here is a technique called Art Direction where we can provide different images for different screen sizes and orientations.

Art direction: The problem whereby you want to serve cropped images for different layouts — for example a landscape image showing a full scene for a desktop layout, and a portrait image showing the main subject zoomed in for a mobile layout. You can solve this problem using the <picture> element.

Resolution Switching

The second problem that also is being helped by the <picture> tag is Resolution Switching

Resolution switching: The problem whereby you want to serve smaller image files to narrow-screen devices, as they don’t need huge images like desktop displays do — and to serve different resolution images to high density/low density screens. You can solve this problem using vector graphics (SVG images) and the srcset with sizes attributes.

Rails picture_tag helper

Rails 7.1 now supports the picture_tag helper which generates a <picture> tag with <source> and <img> tags.

A simple example is as follows:

<%= picture_tag("car.jpeg") %>

This generates the following HTML:

    <img src="/images/car.jpeg" />

Multiple sources

For providing multiple image sources we can do as follows:

<%= picture_tag("car.webp", "car.avif", "car.png",   
                :image => { alt: "Image", class: "responsive-img" }) %>

This generates the following HTML:

    <source srcset="/images/car.webp" />
    <source srcset="/images/car.avif" />
    <source srcset="/images/car.png" />
    <img alt="Image" class="responsive-img" src="/images/car.png" />

Complete example with custom tags

We can also use custom tags- source and image_tag to build a custom picture tag, by passing a block to picture_tag helper-

<%= picture_tag(:class => "responsive") do %>
    <%= tag(:source, :srcset => image_path("car.webp"), media => "(min-width: 600px)") %>
    <%= tag(:source, :srcset => image_path("car.avif"), media => "(min-width: 600px)") %>
    <%= tag(:source, :srcset => image_path("car.png"), media => "(min-width: 600px)") %>
    <%= image_tag("picture.png", :alt => "Image") %>
<% end %>

This generates the following HTML:

    <source srcset="/images/car.webp" media="(min-width: 600px)" />
    <source srcset="/images/car.avif" media="(min-width: 600px)" />
    <source srcset="/images/car.png" media="(min-width: 600px)" />
    <img alt="Image" class="responsive-img" src="/images/car.png" />


The picture_tag helper in Rails is a great addition to support modern web image formats and responsive images out of the box.

Need help on your Ruby on Rails or React project?

Join Our Newsletter