ScreenshotNeo

BlogHow-to

How to Make Vue.js Apps Cross-Browser Compatible

Build a browser support contract for your Vue app, then configure builds, audit dependencies, handle browser APIs and CSS, and test critical flows across real browser engines.

By the ScreenshotNeo team4 October 202610 min read

To make a Vue app cross-browser compatible, first decide which browsers, versions, operating systems, and devices you support. Then check that your Vue version can run there, configure your build tool for those targets, audit dependencies and browser APIs, review CSS behavior, and test important user journeys in the actual browser engines your audience uses.

There is no universal browser list that fits every product. Vue 3 requires native ES2016 support and does not support Internet Explorer 11. Build transformations and polyfills can address some compatibility gaps, but they cannot make Vue 3 run in IE11. If IE11 is mandatory, Vue’s FAQ identifies Vue 2 as an option; Vue 2 reached end of life on December 31, 2023, so that choice requires a deliberate maintenance and migration plan. Vue FAQ: browser support and Vue 2 lifecycle.

1. Define the browser support contract

Write down what “supported” means before changing Babel, CSS settings, or dependencies. A practical support contract identifies:

  • Browser and minimum version, such as Safari on iOS or Firefox on desktop.
  • Operating system and device classes that matter to your users.
  • Whether support means the application loads, critical journeys work, or every feature is supported.
  • Any contractual, accessibility, security, or customer requirements that mandate a specific environment.
  • How you will test the contract and how often you will revisit it.

Use product analytics, support history, customer requirements, and contractual commitments to choose targets. Consider audience share alongside the cost and risk of excluding a browser. Do not copy a generic “latest two versions” policy without checking whether it covers your users.

Decision Question to answer
Audience Which browsers, versions, operating systems, and mobile devices do users actually use?
Framework floor Can this Vue version run in every required browser?
Feature floor Which APIs, CSS features, and dependency requirements do critical journeys rely on?
Verification Which browser engines will run the critical end-to-end checks?
Ownership Who reviews support changes when the audience or toolchain changes?

2. Check Vue’s browser requirements first

Vue’s current FAQ says Vue 3.x supports browsers with native ES2016 support. Internet Explorer 11 is not supported: some language features Vue 3 relies on cannot be polyfilled for legacy browsers. Babel can transform application syntax and polyfills can supply selected APIs, but neither changes that Vue 3 runtime limit. See the official Vue FAQ before promising support.

If IE11 is a hard requirement, assess Vue 2 only as a constrained legacy path. Vue 2 reached end of life on December 31, 2023. Plan for the maintenance, security, and eventual migration implications rather than treating a framework downgrade as a routine build setting.

For a CDN and import-map setup, do not confuse the import-map browser threshold with Vue’s overall browser support. Vue’s Quick Start notes import maps are supported in Safari 16.4 and later; that detail applies to that delivery approach. Consult the Vue Quick Start if you use it.

3. Use the right build setup

For a new project, Vue recommends Vite through the official create-vue scaffolder. Vue CLI is in maintenance mode. Keep Vue CLI configuration advice scoped to existing Vue CLI projects; its Babel and Browserslist recipes are not universal Vite settings. See the Vue tooling guide.

Start a Vite-based Vue project

npm create vue@latest
cd my-vue-app
npm install
npm run dev

The scaffolder asks which project features to include. Select the options your application needs, then commit the generated configuration and lockfile. This is a starting point, not a guarantee that every chosen browser is supported: validate your targets against Vue’s runtime floor and the syntax and APIs your dependencies require.

Existing Vue CLI projects: configure Browserslist deliberately

The following is for an existing Vue CLI application. Its browserslist targets inform JavaScript transpilation and CSS prefixing in that toolchain. Choose targets from your support contract; this example is illustrative and is not a universal browser policy.

// package.json (existing Vue CLI project)
{
  "browserslist": [
    "last 2 Chrome versions",
    "last 2 Firefox versions",
    "last 2 Safari versions",
    "last 2 Edge versions",
    "iOS >= 16"
  ]
}

Review the resulting targets against the audience and Vue version. A target declaration guides transformations and prefixing; it does not guarantee that the framework, every dependency, every CSS feature, or every browser API works in all listed environments. Read the Vue CLI browser compatibility guide for that project type.

4. Audit dependency syntax and browser APIs

Compatibility has separate layers. Transpilation changes JavaScript syntax that a target cannot parse. Polyfills implement selected missing APIs. CSS processing can add prefixes where needed. None of those steps can repair an unsupported framework runtime or a dependency that fundamentally requires a newer browser.

  1. Inspect your production bundle and dependencies. Identify packages that ship syntax newer than your supported targets. Check package documentation and browser requirements; do not assume all dependencies are pre-transpiled.
  2. Transpile only dependencies that need it. In Vue CLI, transpileDependencies opts selected dependencies into Babel processing. This setting is Vue CLI-specific; do not paste it into a Vite project as if it were a shared Vue option.
  3. List API requirements. Find usage of browser APIs such as storage, observers, media, or newer collection methods. Determine whether the target browsers implement them and whether a maintained polyfill is appropriate.
  4. Choose polyfill inclusion intentionally. Vue CLI documents entry-based and usage-based approaches with different dependency-detection and bundle-size tradeoffs. Include only what the application and its targets require.
  5. Verify the production output. A development server can differ from the production build. Test the built application in the target browser engines.

Do not install a large polyfill bundle by default. Extra code can increase download and parse work, while a missing required API can still break a specific flow. Make the decision from the support contract and actual feature usage.

5. Review CSS and browser-specific behavior

Test the behavior users see, not only whether the page parses. Check responsive layout, overflow, fonts, focus indicators, keyboard navigation, form validation, media playback, scrolling, and any CSS features that are essential to a journey. Browser differences can appear in layout and interaction even when JavaScript loads successfully.

Vue CLI’s documented setup uses Browserslist to guide CSS prefixing. For other toolchains, use the current documentation for that toolchain rather than transplanting Vue CLI settings. Prefixing cannot supply a missing layout feature or fix a design that depends on unsupported behavior; provide a fallback or change the implementation when a required browser lacks the feature.

6. Build a small, risk-based browser test matrix

End-to-end (E2E) tests exercise the application through real browser pages. They can reveal routing, state, asset, and request problems that isolated component tests may miss. Vue’s testing guide describes Playwright coverage for Chromium, WebKit, and Firefox. It describes Cypress support for Chromium-based browsers, Firefox, and Electron, with WebKit support marked experimental. Check each tool’s current documentation when selecting versions and configuration.

Matrix row What to include Why
Main audience The most-used browser engine and device class from your analytics Protect the largest group of users.
Distinct engines Representative Chromium, Firefox, and WebKit coverage where relevant Catch engine-specific behavior without testing every browser/version combination on every change.
High-risk environment Any browser or device required by a contract, accessibility need, or critical customer flow Audience averages can hide important obligations.
Framework boundary The oldest supported browser that is still above the Vue runtime floor Catch syntax and API issues near your declared minimum.

Vue cautions that exhaustive cross-browser testing has diminishing returns and consumes more time and machine capacity. Start with critical journeys and representative engines, then expand when a user impact or feature risk justifies it.

Example Playwright smoke test

This example assumes a Playwright project is already configured and your app has a stable sign-in route. Replace the route and assertions with selectors from your application.

import { test, expect } from '@playwright/test';

test('sign-in page is usable', async ({ page }) => {
  await page.goto('/sign-in');
  await expect(page.getByRole('heading', { name: /sign in/i })).toBeVisible();
  await expect(page.getByLabel(/email/i)).toBeVisible();
  await expect(page.getByRole('button', { name: /continue/i })).toBeEnabled();
});

Run the same critical flow in the browser projects that represent your support matrix. Keep the checks focused on user-visible outcomes; add cases for navigation, forms, authentication, essential assets, and failure states according to the product’s risks.

Run important checks in CI

  1. Build the production bundle in CI.
  2. Serve the built app or deploy a staging build in a predictable environment.
  3. Run critical E2E journeys in the selected browser engines.
  4. Retain the browser traces, screenshots, or logs your chosen test runner provides when a check fails.
  5. Review failures against the declared support matrix and distinguish application regressions from infrastructure or test flakiness.
  6. Use parallel execution where it improves feedback time without making results unreliable.

Browser coverage costs time and machine capacity. Keep the matrix small enough to run reliably, and add coverage when analytics, support reports, a new feature, or a customer requirement changes the risk.

7. Troubleshooting common compatibility failures

Symptom Likely cause What to do
Vue 3 app fails in IE11 Vue 3 requires native ES2016 support and excludes IE11. Do not expect Babel or polyfills to make Vue 3 compatible. Revisit the support contract; if IE11 is mandatory, assess the Vue 2 legacy path and its end-of-life implications.
A target browser shows a syntax error before the app starts Application code or a dependency shipped syntax the browser cannot parse. Identify the failing bundle and package, then configure the correct toolchain to transform the code where supported. In Vue CLI, review Browserslist and whether the dependency needs transpileDependencies.
Build succeeds, but a feature throws “is not a function” or “undefined” A required browser API is missing, or the API is used before it is available. Check the target browser’s API support, add a narrowly chosen polyfill when suitable, or implement a fallback. Test the exact feature in the affected engine.
Layout differs between browsers CSS behavior, font metrics, intrinsic sizing, or a feature support difference. Reduce the issue to a small page, inspect computed styles in the affected browser, and add a supported fallback or revise the layout. Do not assume JavaScript transpilation fixes CSS.
Only a third-party widget fails The package may have a newer browser floor or untranspiled syntax. Check the vendor’s browser requirements and shipped artifacts. Upgrade, replace, conditionally load, or transpile it if the selected build tool supports that path.
Works in dev but not after deployment Production output, asset paths, caching, or server behavior differs from the development server. Test the production build in a staging-like environment, inspect failed requests and console errors, and verify base paths and caching.
CI fails intermittently in one browser Timing assumptions, shared state, browser infrastructure, or a real race condition. Use observable conditions instead of fixed sleeps, isolate test data, retain traces, and rerun the failed journey in the same engine before classifying it as flaky.
CSS prefixes are missing in a Vue CLI build Browserslist targets may not include the intended browser, or the project is using a different toolchain. Check the effective Browserslist configuration and the Vue CLI compatibility guide. For Vite, consult current Vite-specific documentation rather than applying Vue CLI settings.

8. Keep compatibility reliable and affordable

  • Track the contract. Store supported targets near the project configuration and document exceptions.
  • Test by risk. Run a compact smoke matrix on routine changes and broader checks for releases or high-risk browser-facing work.
  • Separate failure types. Capture browser console output, network failures, and test-runner artifacts so a browser issue is diagnosable.
  • Control bundle growth. Add only the transforms and polyfills required by the target set.
  • Revisit deliberately. Update targets when the audience, Vue version, dependencies, or contractual requirements change.
  • Budget CI capacity. Each additional engine and device configuration adds runtime and maintenance. Expand the matrix where the expected user-risk reduction justifies the cost.

Do not publish a browser matrix as “tested” unless those browser runs actually took place. A declared support target, a configured build target, and a verified test result are different claims.

Or skip the browser setup

If you need screenshots of your Vue app across pages or environments for review, documentation, or visual checks, ScreenshotNeo provides a website screenshot API and MCP server. A GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo website and API documentation.

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 request failed: ${res.status}`);
await Bun.write('shot.webp', res);
  • Cookie banners are accepted and removed before capture, along with more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Response headers report the page verdict and billing status.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • 1,000 screenshots per month are free with no card. Paid plans start at $5 for 3,000 screenshots; all features are available on every plan.

Sign up free for 1,000 screenshots a month, with no card required.

Frequently asked questions

How do I make my Vue app work in Safari and Firefox?

Check your Vue runtime floor and dependency requirements, include Safari and Firefox engines in a risk-based test matrix, and run critical user journeys in those browsers. The exact minimum versions should come from your audience and support contract.

Does Vue 3 support Internet Explorer 11?

No. Vue 3 requires browsers with native ES2016 support. Babel and polyfills cannot make Vue 3 run in IE11. Vue 2 is a legacy option to assess, but it reached end of life on December 31, 2023.

How do I configure browser support in Vite?

Start from Vue’s current Vite-based tooling and consult the current Vite documentation for build-target configuration. Do not copy Vue CLI’s browserslist and transpileDependencies recipes as universal Vite settings.

Do I need to test every browser and version?

No. Select representative engines and high-risk devices from your audience and requirements. Vue’s testing guide notes that exhaustive cross-browser coverage has diminishing returns and consumes additional time and machine capacity.

Sources