Skip to content

feat: add Picture component for art-directed responsive images - #18

Merged
gioboa merged 2 commits into
QwikDev:mainfrom
intellix:pr/picture-component
Jul 31, 2026
Merged

feat: add Picture component for art-directed responsive images#18
gioboa merged 2 commits into
QwikDev:mainfrom
intellix:pr/picture-component

Conversation

@intellix

@intellix intellix commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What

Issue: #17

Adds a Picture component for art-directed responsive images — serving different image files per viewport (e.g. a full-width desktop banner and a smaller mobile banner) via a native <picture> element.

import { Picture } from 'qwik-image';

<Picture
  layout="fullWidth"
  alt="Banner"
  loading="eager"
  fetchpriority="high"
  src={props.image}                 // fallback / default (desktop)
  sources={[
    { src: props.imageMobile, media: '(max-width: 767px)' },
    { src: props.image,       media: '(min-width: 768px)' },
  ]}
/>

Why

A common pattern for different mobile/desktop banners is two <Image> tags toggled with CSS (hidden md:block). But loading="eager" and fetchpriority="high" are honored by the browser even for display:none elements, so both images get fetched on the critical path — an LCP regression Lighthouse flags.

<picture> with <source media> fixes this at the platform level: the browser evaluates the media queries and downloads only the matching source. loading/fetchpriority on the fallback <img> apply to whichever source is selected, so exactly one request is made and correctly prioritized.

How

  • Reuses the existing Image component as the required fallback <img> child, and the existing getSrcSet/getSizes helpers for each source's responsive srcset.
  • Per-source width/height/aspectRatio overrides (fall back to Picture-level values) for tuning each source's generated srcset.
  • resolutions/imageTransformer$ come from the existing ImageContext, so the global useImageProvider config applies with no extra wiring.
  • Image's public API and behavior are unchangedPicture is a new, additive export.

Tests

Adds picture.spec.tsx — 5 tests via @builder.io/qwik/testing's createDOM — covering: fallback-only render, one <source> per entry with correct media/type, loading/fetchpriority on the <img> (verified as the last child), each source's src flowing through imageTransformer$, and per-source width override affecting that source's srcset.

Note: this also repoints the qwik-image:test nx target to run vitest directly, because the @nrwl/vite:test executor (Nx 19.7.4) is incompatible with the repo's pinned vitest@0.30.1/vite@4.3.1. Happy to split that into a separate change if preferred. CI (.github/workflows/test.yml) currently installs deps but doesn't run the test target — worth adding a test step in a follow-up so these tests execute on PRs.

🤖 Generated with Claude Code

@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2abcd37

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
qwik-image Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

intellix and others added 2 commits July 31, 2026 13:54
Adds a `Picture` component that renders a native `<picture>` element with
art-directed `<source media>` children. The browser downloads only the
source whose media query matches, so serving different desktop/mobile banner
images no longer double-fetches under loading="eager"/fetchpriority="high"
(a common LCP regression when hiding a second <Image> with CSS).

- Reuses the existing Image component as the fallback <img> and the
  getSrcSet/getSizes helpers for per-source responsive srcsets.
- Per-source width/height/aspectRatio overrides (fall back to Picture-level).
- Global useImageProvider config (resolutions, imageTransformer$) applies
  with no extra wiring. Image's public API is unchanged.
- Adds the first component spec (picture.spec.tsx, 5 tests via createDOM) and
  wires the qwik-image test target to run vitest directly (the @nrwl/vite:test
  executor is incompatible with the pinned vitest 0.30/vite 4.3).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gioboa
gioboa force-pushed the pr/picture-component branch from aaee8ef to 2abcd37 Compare July 31, 2026 14:01

@gioboa gioboa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely missed the PR notification. Thanks for this fix, @intellix! 👏

@gioboa
gioboa merged commit 05bb0af into QwikDev:main Jul 31, 2026
1 check passed
@gioboa gioboa mentioned this pull request Jul 31, 2026
@intellix
intellix deleted the pr/picture-component branch July 31, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants