ScreenshotNeo

BlogHow-to

How to Generate HTML Image Links

Learn how to make images clickable in HTML with accessible alt text, responsive sources, new-tab behavior, and practical debugging examples.

By the ScreenshotNeo team1 October 20268 min read

To make an image clickable in HTML, place the <img> element inside an <a> element. Put the destination in the anchor’s href; put the image file in src (or responsive candidates in srcset). Write alt text that describes where the link goes or what it does.

<a href="https://example.com/gallery" aria-label="Open the full-size gallery">
  <img src="/images/thumbnail.jpg" alt="Open the full-size gallery" width="320" height="180">
</a>

The anchor is the interactive control. The image supplies its visible content. This preserves normal keyboard, pointer, browser history, and assistive-technology behavior.

1. The basic pattern

Use this structure when the image should open another page:

<a href="/article.html">
  <img src="/images/article-thumb.webp" alt="Read the article: Coastal birds" width="640" height="360">
</a>

href can be an absolute URL, a root-relative path, a relative path, a fragment, a downloadable file, or another valid navigable target. src identifies the image resource. The two attributes serve different purposes and should not be swapped.

<a href="/images/photo-large.jpg">
  <img src="/images/photo-thumb.jpg" alt="View the larger coastal birds photograph" width="320" height="200">
</a>

This pattern is useful for galleries, documentation diagrams, product photos, and thumbnails. The linked image’s alternative text describes the destination as a text link would.

2. Write useful alternative text

When the image is the only content inside the link, alt should communicate the link’s purpose or destination. “Visit the MDN site” is more useful than “image” because it tells a screen-reader user what activating the control will do.

<a href="https://developer.mozilla.org">
  <img src="/shared-assets/images/examples/favicon144.png" alt="Visit the MDN site" width="144" height="144">
</a>

When to use an empty alt

If visible text in the same anchor already states the destination and the image adds no information, use alt="" so assistive technology does not announce the same purpose twice.

<a href="/downloads/report.pdf">
  <img src="/icons/download.svg" alt="" width="20" height="20">
  Download the report (PDF)
</a>

Do not omit the alt attribute. An omitted value can cause the image filename or URL to be exposed as a less useful substitute.

Functional versus descriptive wording

Link purpose Good alt Weak alt
Open a product page View the trail camera Product image
Open a full-size photo View the larger mountain photograph Mountain
Download a PDF with visible text alt="" Download icon

3. Responsive linked images

Keep the destination on <a href> while supplying multiple image candidates to <img>. The browser chooses an appropriate source based on viewport and display size.

<a href="/products/camera">
  <img
    src="/images/camera-640.jpg"
    srcset="/images/camera-640.jpg 640w, /images/camera-1280.jpg 1280w"
    sizes="(max-width: 700px) 100vw, 640px"
    alt="See the camera product details"
    width="640"
    height="360"
  >
</a>

src is the fallback. Each srcset candidate has a width descriptor, and sizes tells the browser how much layout space the image will occupy. The link target does not change when a different candidate is selected.

Prevent layout shifts

Set intrinsic width and height values that match the image’s aspect ratio. This reserves space before the file finishes loading and keeps the clickable area stable.

4. Opening the destination in a new tab

Add target="_blank" when a new browsing context is genuinely useful, and pair it with rel="noopener". Explain the behavior in nearby text when it may surprise users.

<a href="https://example.com" target="_blank" rel="noopener">
  <img src="photo.jpg" alt="Open Example.com" width="800" height="500">
</a>

Use rel="noreferrer" too when you intentionally want to suppress the referrer header:

<a href="https://example.com" target="_blank" rel="noopener noreferrer">
  <img src="photo.jpg" alt="Open Example.com in a new tab" width="800" height="500">
</a>

A real anchor remains the correct control. Avoid clickable <div> elements and href="javascript:void(0)"; they remove expected link behavior and add unnecessary keyboard and accessibility work.

If you need a current screenshot as the linked image, you can generate the asset first and then use the resulting file URL in src. A browser automation script can visit the page, wait for it to render, save a screenshot, and your HTML can link that screenshot to the original page.

Minimal browser workflow (Playwright)

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'public/example.webp', fullPage: true, type: 'webp' });
await browser.close();

Publish public/example.webp, then reference it from your page:

<a href="https://example.com">
  <img src="/example.webp" alt="Open Example.com" width="1280" height="720">
</a>

For production captures, account for cookie banners, delayed content, lazy-loaded images, bot checks, authentication, failed requests, and pages that never reach network idle. Save a stable file URL and invalidate it when the source page changes.

6. Or skip the browser setup

ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. See the ScreenshotNeo API documentation for the complete parameter list. This example captures a page that you can publish as the linked image:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
await Bun.write('shot.webp', data);

Then make the image a link:

<a href="https://stripe.com">
  <img src="/images/shot.webp" alt="Open the Stripe homepage" width="1280" height="720">
</a>

Before capture, ScreenshotNeo can accept consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Clean shots are billed, while bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. The response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Free accounts include 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

7. Useful capture and delivery options

When generating the source image, choose options that match the link’s purpose:

Need Relevant option Why it matters for a linked image
Long page preview Full-page capture with lazy images loaded Includes content below the initial viewport.
One card or chart Capture one element by CSS selector Keeps the link focused on a specific component.
Theme preview Dark mode Matches the destination’s visual context.
Device-specific preview Device presets, custom viewport, retina scale Produces the dimensions your layout expects.
Consistent branding Custom CSS and JavaScript Adjusts presentation before capture.
Dynamic pages Wait for a selector, delay, or network idle Prevents capturing before important content appears.
Noise reduction Block ads, trackers, requests, or resource types; hide selectors Produces a cleaner thumbnail.
Restricted pages Custom headers, cookies, user agent, Authorization Allows the capture request to reach the intended view.
Regional rendering Timezone and geolocation Matches localized page output.
Transparent cards Transparent background Lets the image blend into the surrounding page.
File constraints Image resizing Fits a fixed card or CMS limit.
Repeated thumbnails Cache with a chosen TTL Reduces duplicate capture work.
Public embeds Signed links Protects image URLs used in public <img> tags.

8. Troubleshooting

Symptom Likely cause Fix
Clicking does nothing The <img> is not inside an anchor or the anchor has no valid href. Wrap the image in <a href="..."> and inspect the rendered DOM.
The wrong page opens The destination was placed in src instead of href. Put the navigation URL on <a href>; keep the image URL on <img src>.
Screen readers announce an unhelpful filename alt is missing or generic. Write functional link text in alt, or use alt="" when visible text already supplies the purpose.
The thumbnail is blurry The selected source is too small or the display uses a high-density screen. Add suitable srcset candidates and set sizes accurately.
The layout jumps while loading No intrinsic dimensions were provided. Set matching width and height attributes or reserve space with CSS.
A new tab creates security concerns target="_blank" lacks an opener policy. Add rel="noopener"; add noreferrer when referrer suppression is required.
Screenshot contains a popup or cookie dialog The page was captured before its overlays were handled. Accept or remove the banner, hide selectors, wait for the page state, or use ScreenshotNeo’s consent and cleanup steps.
Screenshot is blank or incomplete Navigation timed out, content is lazy-loaded, or a bot check blocked rendering. Wait for a selector or delay, load lazy content, inspect verdict headers, and handle blocked pages before publishing the image.
Screenshot request returns an error Invalid URL, credentials, headers, or an unreachable target. Validate the URL, API key, custom headers, cookies, and target availability; use a finite timeout and retry transient failures.

9. Performance, reliability, and cost

  • Serve appropriately sized thumbnails; do not send a full-resolution image when the link displays a small card.
  • Use srcset and sizes so browsers download a suitable candidate.
  • Set intrinsic dimensions to reduce cumulative layout movement.
  • Cache generated screenshots and refresh them with a deliberate TTL when the source changes.
  • For automated capture, wait on a meaningful selector instead of relying only on a fixed delay. A selector-based wait adapts better to variable network speed.
  • Keep the original destination URL in the anchor even if the thumbnail is cached on a different host.
  • With ScreenshotNeo, cache hits are not billed; failed loads, timeouts, blank pages, and bot checks are also not billed. Check X-Page-Verdict and X-Billed before treating a response as a valid clean shot.

10. Testing checklist

  • Activate the image with a mouse, keyboard, and touch input.
  • Confirm href points to the intended page or file.
  • Confirm the image loads over the deployed path, including CDN or subdirectory deployments.
  • Check that alt states the action or destination and is not redundant with visible text.
  • Test the responsive candidates at narrow and wide viewports.
  • Verify new-tab links include rel="noopener".
  • Check focus styling so keyboard users can see the link.
  • For generated screenshots, verify the page verdict, dimensions, freshness, and absence of overlays before publishing.

11. FAQ

Where does the href go?

It belongs on the wrapping <a> element. The image file belongs in <img src>.

Yes. Set the PDF URL as href and provide alternative text such as “Open the annual report PDF.”

Should every linked image open in a new tab?

No. Use a new tab only when it helps the user’s task, and pair it with rel="noopener".

Can I use an SVG?

Yes. An SVG can be the src of an image link, provided it has an appropriate accessible name through alt or nearby visible link text.

Keep one destination on <a href> and add srcset plus sizes to the nested <img>.