Founder & Lead Engineer, RAITHub
To test UI generated by v0, check what the screenshot cannot show: every screen's loading, empty, error and overflow states; keyboard use, labels, contrast and target size against WCAG 2.2; layouts at phone, tablet and desktop widths in light and dark mode; and the server actions behind each form, which must check who is calling. Automate the repeatable parts with Playwright and axe.
If you would rather have your v0 app tested for you, see how RAITHub would test this below.
v0 is very good at the part of front-end work that used to take longest: a clean, consistent, responsive-looking interface from a sentence. That polish is also the trap. A screen that looks finished invites you to ship it, and everyone can build with AI now while almost no one has a tester. This guide is the tester's pass over v0's actual output.
What does v0 actually generate?
v0 describes itself as "an AI agent that helps anyone create real code and full-stack apps" (v0 docs). Its FAQ names the stack: "Next.js, React, TypeScript, Tailwind CSS, and shadcn/ui" (v0 FAQs). Databases come from integrations such as Neon, Supabase and Upstash, and apps publish to Vercel (v0 quickstart).
That shapes the test plan in three ways:
- Components are your source code. shadcn/ui describes itself as "a set of beautifully-designed, accessible components and a code distribution platform" (shadcn/ui docs), and its interactive components can sit on headless primitives such as Radix UI, Base UI or React Aria (shadcn/ui dialog docs). The primitives handle keyboard support and focus. Radix's own docs add the caveat: "Ultimately it's up to you to provide those labels" (Radix accessibility docs).
- Forms often post to Server Actions. Next.js says a Server Action "is reachable via a direct POST request, not just through your application's UI", and that you should "verify authentication and authorization inside each one" (Next.js data security guide). A hidden button is not a permission check.
- Environment variables have a public prefix. In Next.js, variables prefixed
NEXT_PUBLIC_go to the browser. v0 "analyzes NEXT_PUBLIC_ usage and warns users about potential security risks" (v0 security docs). The Supabase integration on Vercel installs both a public key and aSUPABASE_SECRET_KEY(Vercel Supabase integration); the second must never reach a client component.
Which states does a v0 screen usually skip?
A prompt describes the screen with data in it. Users see it before the data arrives, with none, with too much and when the request fails. This is engineering guidance on generated UI in general, not a count from audits.
| State | What to check | Typical failure |
|---|---|---|
| Loading | Skeleton or spinner; layout does not jump when data arrives | Blank area, or content shifting under the user's tap |
| Empty | A message and a next step for a new user with no data | An empty table with headers and nothing else |
| Error | A plain message, a retry, and the form input preserved | A stuck spinner, or a stack trace in the page |
| Overflow | Long names, long emails, 40-character words, 1,000 rows | Text spilling out of cards, tables wider than the phone |
| Permission | A signed-out user, and a user without the role | Admin controls visible, or a crash instead of a redirect |
| Partial | Optional fields missing, images that fail to load | "undefined" on screen, broken image icons |
| Interaction | Double submit, back button, refresh mid-form | Duplicate records, lost input |
Ask v0 for each state explicitly, then test that it exists. A prompt such as "add loading, empty and error states to this table, and handle names up to 80 characters" works far better than finding the gap after launch.
How do I test accessibility in v0-generated UI?
Start from the most common failures on the web. The WebAIM Million 2026 report found detected WCAG failures on 95.9% of a million home pages; the top issues were low-contrast text (83.9% of pages), missing image alt text (53.1%), missing form labels (51%), empty links (46.3%) and empty buttons (30.6%). Good primitives prevent some of these, but not the ones that depend on content and styling:
- Icon-only buttons need an accessible name, such as
aria-label. Generated toolbars and table row actions often have none. - Contrast in both themes. Muted grey text that passes in light mode can fail in dark mode, and the reverse.
- Labels on every input, including search boxes and filters that only have placeholder text.
- Target size. WCAG 2.2 success criterion 2.5.8 requires pointer targets of "at least 24 by 24 CSS pixels", with exceptions (W3C). Small icon buttons in dense tables are the usual miss.
- Focus not obscured. WCAG 2.2 also added 2.4.11: a focused control must not be entirely hidden behind content such as a sticky header or cookie bar (What's new in WCAG 2.2). Tab through the page and watch.
Automate the detectable part, then test by hand. Playwright's docs are clear that automated checks "can detect some common accessibility problems" but "many accessibility problems can only be discovered through manual testing" (Playwright accessibility testing). The accessibility testing checklist covers the manual pass.
What does an automated check look like?
One Playwright file can cover accessibility rules, sideways scrolling at three widths, dark mode, and the empty and error states:
import { test, expect } from '@playwright/test'
import AxeBuilder from '@axe-core/playwright'
const viewports = [
{ name: 'phone', width: 375, height: 667 },
{ name: 'tablet', width: 768, height: 1024 },
{ name: 'desktop', width: 1280, height: 800 },
]
for (const vp of viewports) {
for (const colorScheme of ['light', 'dark'] as const) {
test('dashboard, ' + vp.name + ', ' + colorScheme, async ({ page }) => {
await page.setViewportSize({ width: vp.width, height: vp.height })
await page.emulateMedia({ colorScheme })
await page.goto('/dashboard')
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
.analyze()
expect(results.violations).toEqual([])
const scrollsSideways = await page.evaluate(
() => document.documentElement.scrollWidth > window.innerWidth,
)
expect(scrollsSideways).toBe(false)
})
}
}
test('dashboard shows empty and error states', async ({ page }) => {
await page.route('**/api/projects', (route) => route.fulfill({ json: [] }))
await page.goto('/dashboard')
await expect(page.getByText('No projects yet')).toBeVisible()
// The most recently added route wins.
await page.route('**/api/projects', (route) => route.fulfill({ status: 500, body: 'error' }))
await page.reload()
await expect(page.getByRole('alert')).toBeVisible()
})
Two notes. page.route only intercepts requests the browser makes; data fetched in a Server Component never passes through it, so test those states with a seeded empty account and by pointing a test deployment at a failing service. And change the text and roles to match your screens; if there is no element with the alert role, the error state may not be announced to screen reader users.
How do I test responsiveness beyond resizing the browser?
Resizing a desktop window misses touch, the on-screen keyboard and real font rendering. Test on an iPhone in Safari and a mid-range Android phone in Chrome, and check:
- Forms with the keyboard open: is the submit button reachable, does the page jump?
- Tables: do they scroll inside their container, or do they make the whole page scroll sideways?
- Sheets, dialogs and dropdowns: do they fit, scroll and close on a small screen?
- Landscape, and the user's larger system font size.
The cross-browser testing checklist lists which browsers and devices to cover in 2026.
What should I test behind the UI?
- Every Server Action and route handler, called directly with no session and with another user's session acting on a record that is not theirs. Expect a refusal. The vibe-coded app security checklist lists the rest.
- The browser bundle, searched for secret key prefixes. Anything with
NEXT_PUBLIC_is public by design. - Row-level security, if the app uses Supabase from the browser; see the RLS fix.
- The deployed site, not the v0 preview, with production environment variables. Why AI apps break in production covers the usual causes.
How long does it take to test v0 UI yourself?
For an app with ten to fifteen screens, about two to three days if you can read React: half a day to list the states per screen, a day to set up and run the Playwright and axe checks, half a day of keyboard and screen reader checks, and half a day on real phones. These are estimates, not a quote. The main risk of doing it yourself is trusting the polish: a screen that looks finished gets less scrutiny, and accessibility tools catch only part of what a person using a keyboard or screen reader meets.
Buy, build or hire?
| Route | Choose this when |
|---|---|
| A tool or SaaS testing platform (axe, Lighthouse, visual regression tools, cloud browser grids) | You want fast, repeatable checks on every deploy. Add the Playwright file above whatever else you choose. |
| Freelancers or crowdtesting | You need many real devices and screen readers quickly and can triage the results. |
| An in-house QA hire | You ship UI changes daily and need someone who knows the product and its users. |
| A managed QAaaS team | You want states, accessibility, devices and the server side checked before launch, with a ranked report, without hiring. |
Why RAITHub for this
- The same stack. RAITHub builds in Next.js, React, TypeScript and Tailwind; this website, built on that stack, runs 400+ tests.
- Accessibility audits to WCAG 2.2 AA, with each issue reported with its fix. They do not certify legal compliance with the ADA, the European Accessibility Act or Section 508; that is general information, so confirm legal duties with your adviser.
- Honest about proof. There is no published case study yet of testing a v0 app; the figures above are from software RAITHub built.
When you don't need RAITHub
- It is a landing page or prototype with no accounts or forms that store data. Run the Playwright file and a manual keyboard pass.
- You need a legal accessibility certification or a certified penetration test. RAITHub provides neither.
- You want a tester placed in your team under your management. RAITHub does not offer staff augmentation.
How RAITHub would test this
- State inventory: loading, empty, error, overflow, permission and interaction states for every screen, tested and missing ones listed.
- Accessibility pass: automated axe checks plus keyboard and screen reader testing against WCAG 2.2 AA, in light and dark mode.
- Devices: the main journeys on real iPhones and Android phones and the common desktop browsers.
- Behind the UI: direct calls to Server Actions and route handlers, a search of the bundle for secrets, and checks on the deployed site.
What you buy: a fixed-price launch audit, then an optional monthly QA plan as v0 keeps generating changes. You receive: a ranked bug report with screenshots, reproduction steps and a suggested fix for each issue, the Playwright tests in your repository, and full IP under NDA. See AI-built app testing, accessibility testing and QA as a service. Next step: a free 15-minute call, then a written fixed quote.
Shipping a v0 app soon? Ask for a launch audit quote.
Frequently asked questions
Is v0-generated UI accessible by default?
It starts from a good base: shadcn/ui components on primitives that handle keyboard support and focus. Labels, alt text, contrast, target sizes and content order still depend on what was generated for your screens, so test them.
Which states should every v0 screen have?
Loading, empty, error, overflow with long or plentiful data, a permission state for users without access, and safe handling of double submits and refreshes. Ask v0 for each explicitly, then test that it works.
Are Server Actions in a v0 app secure?
Only if each one checks the session and the caller's right to the specific record. Next.js says Server Actions are reachable by direct POST requests, so call them directly in testing and expect a refusal.
Can automated tools test v0 UI fully?
No. Tools such as axe catch a share of accessibility problems and Playwright catches layout and state regressions. Keyboard and screen reader use, real phones and judgement about content still need a person.
Does testing in the v0 preview count?
It helps while building. Sign off on the deployed site with production environment variables, on real devices, because that is what users get.
Can RAITHub fix the issues it finds?
Yes, under a separate fixed quote, or you can fix them in v0 yourself: each issue in the report comes with reproduction steps and a suggested fix you can use as a prompt.
Related posts
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.