Simon Willison released the <click-to-play> web component on June 17, 2026. The tool gives developers a zero-dependency way to defer animated GIF loads until a user explicitly clicks play. The ~1 KB custom element wraps a static poster frame and link, swapping in the full GIF only on interaction. This progressive enhancement pattern works without JavaScript and requires no build step.
Animated GIFs remain ubiquitous in technical documentation, incident reports, and social media embeds. Each file can weigh multiple megabytes and auto-plays as soon as the page loads.
Browsers still lack a native loading="lazy" equivalent for <img> elements serving GIF content, per MDN’s documentation of the <img> element’s loading attribute. Existing workarounds including IntersectionObserver swaps, <video> transcoding, or heavy JavaScript libraries add implementation complexity or require build steps.
Willison’s component targets that gap with a progressive enhancement approach. The markup functions without JavaScript, and the component “enchants” it only when the browser supports custom elements, per the MDN guide to using custom elements.
How the <click-to-play> markup works
The component expects a specific, semantic HTML structure to function:
<click-to-play>
<a href="URL to full GIF">
<img src="URL to first frame or poster image" alt="Descriptive text for the GIF content">
</a>
</click-to-play>
Key structural elements include:
– Outer <click-to-play>: registers as a native custom element in the browser
– <a>: points to the full GIF URL, remaining fully functional even if JavaScript fails to load
– <img>: serves the first frame or a curated poster image as a lightweight static placeholder
When the component upgrades, it injects a play button overlay. It swaps the still image for the full GIF on user click, and preserves the link as a fallback for non-JavaScript environments, per Willison’s original announcement of the <click-to-play> component.
Across three common implementation scenarios, the component changes default loading behavior. When JavaScript is disabled or fails to load, pages using the component render a static poster frame with a direct link to the full GIF, rather than auto-playing the animation. For users with JavaScript enabled who do not interact with the GIF, only the lightweight static poster loads, eliminating the full animation’s bandwidth cost. When a user clicks the injected play button, the browser fetches and swaps in the full animated GIF on demand.
Why progressive enhancement matters here
Progressive enhancement is a risk-reduction strategy, not a rigid set of rules. The pattern ensures content remains accessible to search engine crawlers, users in restricted browsing environments, and users on flaky network connections.
It also eliminates layout shift from late-loading play buttons, as the static poster frame occupies the final rendered dimensions of the GIF. The component has zero runtime dependencies, with a ~1 KB minified footprint that uses only the standard Custom Elements API, per the MDN guide to using custom elements.
Willison tags the release with the progressive-enhancement and web-components labels. This signals alignment with the Extensible Web Manifesto principles that have guided his work since the early days of the Django web framework, per Willison’s original announcement of the component.
Developer experience: drop-in, no build step
For teams maintaining static sites, Markdown content pipelines, or CMS-rendered content, the component fits existing authoring workflows with no changes to tooling.
The implementation process requires three steps:
1. Generate a poster frame (either the first frame of the GIF or a custom designed thumbnail) during existing asset processing workflows
2. Emit the wrapper <click-to-play> markup in the final HTML output, with no need for a bundler or framework-specific hooks
3. Include the component script via a single <script type="module" src="..."> tag once per page
The component’s single responsibility of GIF deferral means it composes cleanly with other common enhancements. These include lazy-loading images, syntax highlighters, and copy-to-clipboard buttons, with no risk of version conflicts.
Performance implications for real pages
A typical technical blog post that includes three to five animated GIFs can exceed 10 MB of eager image payload. Deferring those assets until explicit user interaction delivers measurable performance gains.
It reduces Largest Contentful Paint (LCP) contention on initial page load. It lowers Total Blocking Time (TBT) by removing GIF decode work from the browser’s critical rendering path.
It also respects data caps for mobile users who may never tap to load every animation on the page. The component does not replace modern video formats like AVIF and WebM for net-new content. It instead addresses the long tail of existing GIF assets that teams cannot easily re-encode or migrate.
Constraints and considerations
The component has three key constraints for implementers to account for. First, the GIF URL must be fetchable by the browser, with standard cross-origin restrictions applying normally per same-origin policy. Second, the design intentionally omits autoplay-on-hover or autoplay-when-visible functionality to preserve an explicit-consent model for users. Third, developers can target the injected play button via CSS custom properties, with shadow DOM parts potentially exposed for styling in future component versions.
Broader context: web components in 2026
<click-to-play> launches at a time when native custom elements enjoy full baseline support across Chrome 54 and later, Firefox 63 and later, Safari 13.1 and later, and Edge 79 and later.
The web components ecosystem has shifted from polyfill-heavy experimental projects to production-grade primitives. Examples include <model-viewer> for 3D model rendering and <details-utils> for enhanced disclosure widgets, alongside focused single-purpose components like this one, all cataloged on WebComponents.org.
Willison’s release follows his established pattern of shipping small, composable tools, including Datasette, sqlite-utils, and shot-scraper, rather than monolithic frameworks. For maintainers, this approach delivers auditable surface area and predictable upgrade paths.
Frequently asked questions
This section covers common user questions about the component’s functionality and constraints.
Does this work without JavaScript?
Yes. The <a> plus <img> fallback structure renders a static poster frame linking to the full GIF even if JavaScript is disabled or fails to load. No JavaScript is required for the basic fallback functionality to work.
What is the component’s file size?
The component is ~1 KB minified, with zero external dependencies. It uses only the standard Custom Elements API built into all supported browsers, per Willison’s original announcement of the component.
Can I style the injected play button?
Yes. The current version exposes the play button for CSS targeting. Shadow DOM parts may be exposed for styling in future component releases.
Does the component support autoplay on hover or when visible?
No. The design intentionally requires an explicit user click to load the GIF, preserving user consent and avoiding unnecessary data usage for users who never interact with the animation.
What browsers are supported?
All modern browsers with Custom Elements v1 support: Chrome 54 and later, Firefox 63 and later, Safari 13.1 and later, and Edge 79 and later.
Takeaway: a pragmatic primitive for a persistent format
Animated GIFs are not disappearing from the web. Incident timelines, UI regression captures, and community memes will continue to generate them for the foreseeable future.
<click-to-play> gives developers a standards-based, zero-dependency lever to stop paying the bandwidth tax for animations users never opted in to load.
Adopt the component in any context where GIFs are currently used on performance-critical sites. Replace GIFs with modern video formats in workflows that support re-encoding existing assets. The component does not require a full site rewrite to deliver immediate performance gains.
Bottom line: For any site serving three or more animated GIFs per page, implementing Simon Willison’s <click-to-play> component will reduce initial page weight by up to 10 MB per page with no build step, no framework dependency, and a ~1 KB footprint — a zero-risk performance win that preserves content access for users without JavaScript.
