Reviewing a Grav theme change usually starts well and ends badly. You fix a header on the homepage, check it in one browser at one width, and ship it. Two days later someone reports that the same header collapses oddly on a taxonomy listing page, or that a long page title breaks the grid on a product page nobody thought to check. Grav's flat-file, page-tree structure makes this worse in a subtle way: every page can carry its own frontmatter, its own template override, and its own content shape, so "the theme" is really dozens of slightly different rendering contexts.
A visual acceptance matrix is a simple discipline for catching this before merge: a short, explicit list of route/viewport/content combinations that must be checked whenever CSS or template logic changes, instead of relying on whichever page happens to be open in your browser.
Start with the routes that actually represent your content, not the ones that are easiest to open. For most Grav sites that means: the homepage, a standard content page, a listing or blog page, a page with a long title or missing hero image, and a page using a modular or nested layout. Those five or six routes usually expose most layout assumptions.
Encode the acceptance criteria in frontmatter so they travel with the page. This keeps the checklist next to the content it applies to, rather than in a separate document that goes stale.
title: Product Detail Fallback
---
review:
matrix:
- viewport: mobile
expect: "hero image collapses without overlapping price"
- viewport: tablet
expect: "sidebar moves below content, no horizontal scroll"
- viewport: desktop
expect: "gallery and description align on shared baseline"
content_state: missing_image
Surface that data in the template during review so it's visible, not just documented. A small Twig block can print the expected conditions directly on the page while you're testing, then be hidden or stripped for production.
{% if config.environment == 'review' and page.header.review.matrix %}
<div class="review-matrix">
<ul>
{% for check in page.header.review.matrix %}
<li><strong>{{ check.viewport }}:</strong> {{ check.expect }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
This is deliberately low-tech. It won't catch pixel-level regressions, and it doesn't replace real device testing, but it forces reviewers to look at the same defined states every time instead of improvising.
The main tradeoff is coverage versus effort. A matrix with every page and every breakpoint is thorough but unrealistic to maintain by hand. A matrix limited to three or four representative content states is sustainable and still catches the majority of layout regressions, because most breakage comes from a handful of structural assumptions (long titles, missing media, nested modules) rather than from every possible page.
When you're deciding how a layout should behave before writing the CSS, it can help to have a reference image to compare against rather than describing the target state in words alone. Tools built for generating or refining reference visuals from a prompt or an existing screenshot, such as Muse Image, can be used outside your Grav workflow to produce a quick mockup of how a hero section or product layout should look in a given state, which then becomes the visual target for one row of your matrix. This is a separate, optional step — there's no integration between Grav and the tool, and it doesn't automate the review itself; it simply gives you something concrete to check the rendered page against.
It's worth being clear about what this approach doesn't do. It won't detect regressions automatically, it depends on someone actually running through the checklist, and it says nothing about performance, accessibility, or JavaScript-driven states. For teams that need automated coverage, this matrix is better treated as a manual review discipline that complements, rather than replaces, any visual regression tooling already in place.
Used consistently, though, a small acceptance matrix turns "does the theme look right" from a vague impression into a short, repeatable checklist — which is usually enough to catch the layout breaks that matter before they reach production.