Catch unintended React UI changes with Vitest snapshots
Use Vitest snapshots to detect unexpected React render changes, then review diffs before accepting updates.
19 May 2026, 20:18 UTC

The problem: a refactor changed the UI, and no one noticed
You rename a React component’s CSS class or remove a prop, and the tests still pass. Weeks later, a customer reports that the button looks wrong in production. Explicit assertions often cover behavior—click handlers, disabled states, text content—but they rarely capture the entire rendered tree. A small styling change can slip through.
The useful takeaway: Vitest snapshot testing stores a serialized version of your component’s output and fails the test when that output changes. It is a regression net for the UI, not a replacement for assertions about what the component does.
What a snapshot actually captures
A snapshot is a plain text file, conventionally named Component.test.tsx.snap and stored in a __snapshots__ directory. When you call toMatchSnapshot(), Vitest serializes the value you pass it—often a string of rendered HTML—and writes it to that file. On later runs, Vitest compares the new render against the saved text and reports a diff if they differ.
This works with any renderer that returns a serializable tree, including React Testing Library. Vitest does not render the component itself; your test renders it, and Vitest snapshots the result.
Worked example: snapshot a React button
Install the dependencies in your project root. This command requires write access to package.json and node_modules.
npm install --save-dev vitest @testing-library/react jsdom
Configure Vitest to use jsdom so DOM APIs are available during tests:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
environment: 'jsdom',
},
})
Create a test for a simple button component:
import { render } from '@testing-library/react'
import { describe, it, expect } from 'vitest'
import Button from './Button'
describe('Button', () => {
it('matches the saved render output', () => {
const { container } = render()
expect(container.innerHTML).toMatchSnapshot()
})
})
Run the test suite from the project root:
npx vitest run
The first run creates __snapshots__/Button.test.tsx.snap and the test passes. On subsequent runs, Vitest compares the rendered HTML against that file.
Now change the component, for example by renaming variant='primary' to variant='secondary' or altering the markup. Run npx vitest run again. The test fails and Vitest prints a diff showing which HTML attributes or tags changed.
Review before you update
When a snapshot fails, decide whether the change is intentional. If it is, refresh the snapshot:
npx vitest --updateSnapshots
This command writes to __snapshots__ files, so it changes state. Review the diff output first, then inspect git diff __snapshots__ before committing. If the change was accidental, revert the component instead; the snapshot acts as a guardrail.
Rollback for a mistaken update: git restore __snapshots__ returns the snapshot files to their last committed state.
Trade-offs and limitations
- Snapshots assert output, not behavior. A component can render the same HTML but handle clicks incorrectly.
- Dynamic values such as timestamps, random IDs, or dates make snapshots flaky because they change on every render.
- Large snapshot files are tedious to review, and pull requests can include snapshot updates that nobody reads.
Pair snapshots with explicit assertions for critical behavior. For the button example, add checks for the label and type alongside the snapshot:
const button = screen.getByRole('button', { name: 'Save' })
expect(button).toHaveAttribute('type', 'button')
expect(container.innerHTML).toMatchSnapshot()
Practical check
- Run
npx vitest runand confirm a.snapfile appears in__snapshots__. - Open the snapshot file and verify it contains the expected HTML.
- Make a deliberate UI change, run the tests again, and confirm the failure diff shows your change.
- If the change is intended, run
npx vitest --updateSnapshots, reviewgit diff __snapshots__, then commit.
Snapshots are most valuable when they catch changes you did not mean to make. Use them to protect the rendered tree, and keep explicit assertions for the behavior your users actually depend on.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.