# Missing viewport meta tag

> Without a viewport meta tag, mobile browsers render your page at desktop width. Add one line to make the layout responsive again.

_Category: Web essentials · Detector `web-essentials` · Check `viewport` · Severity: error_

Without `<meta name="viewport">`, mobile browsers assume a ~980px desktop canvas and shrink the whole page to fit, so text is unreadable and tap targets are tiny. AI scaffolds often generate the component tree but leave the base HTML document untouched, so this one line never gets added. It is the single biggest reason an otherwise-fine page looks broken on a phone.

## Symptoms

- Page looks zoomed-out on mobile — everything is tiny
- Users have to pinch-to-zoom to read or tap anything
- CSS media queries never fire because the layout viewport is 980px, not the device width
- Lighthouse flags "Does not have a <meta name="viewport">"

## How VibeCheck detects it

The `web-essentials` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Missing viewport meta tag`
- **Threshold:** No <meta name="viewport"> present in the document head

## Root causes

- The framework template (`index.html` / `app.html`) was edited to remove it, or a hand-rolled HTML shell never had it
- Meta tags are managed in a head library but the viewport was never configured
- A generated single-file export dropped the document `<head>`

## The fix

Add a viewport meta tag to the document head. `width=device-width` tells the browser to use the physical device width as the layout viewport; `initial-scale=1` disables the initial zoom. Do not set `maximum-scale` or `user-scalable=no` — that breaks accessibility for users who need to zoom.

### Steps

1. Open your document head (`index.html`, `app.html`, or your framework’s metadata config)
2. Add `<meta name="viewport" content="width=device-width, initial-scale=1">`
3. Reload on a real phone or device-emulation and confirm the layout uses the full width

_The canonical viewport tag_

```html
<meta name="viewport" content="width=device-width, initial-scale=1" />
```

## Framework-specific fixes

### React

A plain Vite/CRA React app renders into a static `index.html`. The viewport tag lives there, not in a component — React never touches `<head>` unless you add a head manager.

_index.html_

```html
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
```

### Next.js

Next.js App Router owns the viewport through the dedicated `viewport` export (do not hand-write the tag — Next injects it). Export it from any layout or page; it merges with the document head automatically.

_app/layout.tsx_

```tsx
import type { Viewport } from 'next'

export const viewport: Viewport = {
  width: 'device-width',
  initialScale: 1,
}
```

[Next.js docs](https://nextjs.org/docs/app/api-reference/functions/generate-viewport)

### Vue

Vite-based Vue apps mount into `index.html`. Add the tag there; for meta you set at runtime, use `@unhead/vue`’s `useHead`.

_index.html_

```html
<meta name="viewport" content="width=device-width, initial-scale=1" />
```

### Svelte

SvelteKit’s document shell is `src/app.html`. The viewport belongs there, alongside `%sveltekit.head%`.

_src/app.html_

```html
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  %sveltekit.head%
</head>
```

### Vanilla JS

Put it in the static `<head>` of every HTML entry point. If you template pages server-side, add it to the shared layout partial.

```html
<meta name="viewport" content="width=device-width, initial-scale=1" />
```

## FAQ

### Should I set `user-scalable=no` or `maximum-scale=1`?

No. Disabling zoom is a WCAG accessibility failure — users with low vision rely on pinch-to-zoom. `width=device-width`, `initial-scale=1` is all you need.

### Does Next.js add the viewport tag automatically?

Next injects a sensible default, but you should declare the `viewport` export explicitly so it is intentional and reviewable. Never hard-code the `<meta>` tag in Next’s App Router.

### Why does my media query not work on mobile without this tag?

Without the viewport tag the layout viewport defaults to ~980px, so min-width/max-width breakpoints compare against 980, not the real device width. The tag makes the layout viewport equal the device width.

## Related problems

- [Missing charset declaration](https://vibecheck.wcgw.fun/fix/missing-charset.md) — Web essentials
- [Missing lang attribute on <html>](https://vibecheck.wcgw.fun/fix/missing-lang-attribute.md) — Web essentials
- [Missing favicon](https://vibecheck.wcgw.fun/fix/missing-favicon.md) — Web essentials

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/missing-viewport-meta. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
