Progressive image

Active Storage images with low-resolution previews and explicit lifecycle states.

Source
app/components/nitro_kit/progressive_image.rb
API
NitroKit::ProgressiveImage.new(attachment:, alt:, size: :md, decorative: false)

Progressive loading

A decorative low-resolution variant covers the full image until browser decoding succeeds.

Workspace illustration

ViewportFull width
Rubytest/dummy/app/components/gallery/components/progressive_image_page.rb
render NitroKit::ProgressiveImage.new(
  attachment: image_attachment,
  alt: "Abstract indigo workspace illustration",
  size: :lg,
  id: "gallery-progressive-image-loaded"
)

Resolution sizes

Closed sizes request predictable one- and two-density Active Storage variants without accepting arbitrary processing options.

Variant scale

SM
MD
LG
Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/progressive_image_page.rb
NitroKit::ProgressiveImage::SIZES.each do |size|
  sample(size.to_s.upcase, slug: size) do
    render NitroKit::ProgressiveImage.new(
      attachment: image_attachment,
      alt: "Abstract indigo workspace illustration",
      size:,
      id: "gallery-progressive-image-#{size}"
    )
  end
end

Missing and broken media

Empty markup is complete on the server; failed loads reveal the fallback while preserving informative alt text.

Fallback states

Empty attachment
Failed variant
Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/progressive_image_page.rb
sample("Empty attachment", slug: "empty") do
  render NitroKit::ProgressiveImage.new(
    attachment: nil,
    alt: "Workspace cover",
    size: :sm,
    id: "gallery-progressive-image-empty"
  )
end
sample("Failed variant", slug: "error") do
  render NitroKit::ProgressiveImage.new(
    attachment: broken_attachment,
    alt: "Unavailable workspace cover",
    size: :sm,
    id: "gallery-progressive-image-error"
  )
end

Accessibility intent

The placeholder never enters the accessibility tree; decorative full images also use an empty alt.

Decorative media

Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/progressive_image_page.rb
render NitroKit::ProgressiveImage.new(
  attachment: image_attachment,
  alt: nil,
  decorative: true,
  size: :md,
  id: "gallery-progressive-image-decorative"
)

Record composition

Progressive media, a card, status, and record details compose without utility classes or helper registration.

Workspace overview

ViewportFull width
Rubytest/dummy/app/components/gallery/components/progressive_image_page.rb
render NitroKit::Card.new(id: "gallery-progressive-image-card") do |card|
  card.full_width do
    render NitroKit::ProgressiveImage.new(
      attachment: image_attachment,
      alt: "Abstract indigo workspace illustration",
      size: :lg,
      id: "gallery-progressive-image-card-media"
    )
  end
  card.title(SUMMARY.title, level: 3)
  card.body do
    render NitroKit::DetailsTable.new(SUMMARY, id: "gallery-progressive-image-card-details") do |details|
      details.field(:owner)
      details.field(:status) do |status|
        render NitroKit::Badge.new(
          status.to_s.humanize,
          id: "gallery-progressive-image-card-status",
          color: :success,
          size: :sm
        )
      end
      details.field(:updated_on)
    end
  end
end