Testing your theme
A pre-publish routine for verifying a complete Salieno theme: local install, a full surface checklist, light/dark, mobile, forms, and common traps.
On this page
Testing your theme#
A Salieno theme is only finished when every public surface renders correctly, in both colour modes, on a phone, with its forms still submitting. Because Core ships with no default theme and privileges none, there is no sibling theme to quietly borrow a missing view from — your theme must ship every view it needs, or the site breaks the moment a customer reaches the gap. This article is the pre-publish routine: install locally, walk a completeness checklist, test light and dark and mobile, confirm forms still work, and avoid the handful of traps that pass a quick glance but fail in production.
Do all of this before you cut a marketplace version. Publishing is covered in Publishing & updating; here you make sure there is nothing left to fix.
Install locally#
Local development is a drop-in. No zip, no signing, no marketplace round-trip.
- Put your theme directory at
resources/views/themes/{name}/(the scaffolder does this for you — see Quickstart). If you started from the reference theme,php artisan template:scaffold my-theme --from=salienoclones a complete, working starting point;--minimalwrites a bare skeleton instead. - Publish its assets so
themeAsset()URLs resolve. Activating through the admin does this, or run the asset publish step your workflow uses — the compiled files underassets/are copied topublic/assets/themes/{name}/. - Activate it in Admin → Frontend → Themes. Activation writes the operator's stored choice (
session('template') ?? gs('active_theme')); nothing about it is hardcoded. - Load the storefront. If the theme is active but a page throws a "View not found" error, that is the point of this article — a missing view is a bug you must fix, not something Core papers over. See The fallback story below.
Re-run the asset publish step every time you change a CSS or JS file — the browser is served the copy in public/, not the source under your theme. See CSS, JavaScript & images.
The completeness checklist#
Open every one of these in a browser and confirm it renders — not just the happy path you designed against, but each real surface a customer can reach. A theme that renders home beautifully and 500s on cart/checkout is not shippable.
Marketing & content
home— the home page, rendered from its section list- Every section in
sections.json→secs. Assign each product/landing page in the admin page-builder so its sections actually render, then open each page. The reference theme ships ~65 section slugs (hero, features, pricing, faq, domain_table, testimonials, and the per-product banners); you only need the ones your theme defines, but open each one you ship. pricing— the pricing pagecontact— the contact page (has a form; see forms below)- Static pages:
page,pages,policy,cookieif you ship them
Store & ordering
products/category— a product category listingproducts/order— the product configure/order screen (Livewire; the real cart entry point)store/compare-page— the plan comparison table, if you ship/compare
Domains
domains/index— the domains landing pagedomains/search— search resultsdomains/transfer— the transfer pagedomains/pricing— the TLD pricing tabledomains/configure— post-search domain configuration
Cart & checkout
cart/index— the cartcart/checkout— checkoutcart/confirmation— the post-order confirmation
Authentication — all 8 pages (Livewire components under App\Livewire\Client\Auth\*, each returning view(themeViewName('auth.login'))->layout(themeViewName('layouts.app')); see Authentication pages):
auth/loginauth/registerauth/forgot-passwordauth/reset-passwordauth/verify-emailauth/two-factor-verifyauth/authorizationauth/complete-profile
Error pages — all 6 (resolved as activeTheme().'errors.'.$code in bootstrap/app.php):
errors/403errors/404errors/419errors/429errors/500errors/503
Trigger them for real, not just by visiting the file: hit an unknown URL for 404, submit a form with a stale CSRF token for 419, and (in a non-production build) let an exception through for 500. maintenance is a separate top-level view — open it too if you ship it.
Knowledge base
kb/indexkb/categorykb/articlekb/search
Keep this list next to you and tick each surface off. The completeness bar is binary: every view a controller or Livewire component can ask for must exist in your theme.
Test light and dark#
If your theme.json declares "supports": { "dark_mode": true }, then every surface above has to be checked twice. Dark mode is where half-converted markup shows up — a card that forgot its dark: variant, a hardcoded #fff background, an icon that vanishes on a dark canvas.
Toggle the mode switcher (the reference theme gates it behind settings.show_mode_switcher) and re-walk the checklist, or at minimum re-check every page that carries a distinct surface: home, pricing, a product order screen, checkout, one auth page, one error page, a KB article. Watch for:
- Text with no dark variant (dark grey on near-black)
- Surfaces that stay white in dark mode (a missing
dark:bg-*) - Borders and shadows that disappear or turn into hard lines
- SVG illustrations with baked-in light-mode fills
Colour tokens and the switcher itself are covered in Colours, dark mode & the mode switcher.
Test mobile and responsive#
Open the site in your browser's device emulator at a phone width (375px is a good floor) and re-check the surfaces that carry dense layout: pricing tables, the plan comparison table, the product order screen, checkout, and any multi-column section. Confirm:
- No horizontal scroll on the
body— wide tables and comparison grids must scroll inside their own container, not push the page sideways. - Navigation collapses to a working mobile menu.
- The pricing cycle switcher and plan cards stack legibly.
- Tap targets are large enough and forms are usable one-handed.
Test at a mid tablet width too — the awkward breakpoints are usually between phone and desktop, not at the extremes.
Confirm forms still submit#
This is the failure mode that a visual pass misses entirely: the page looks perfect and the form does nothing. Storefront forms are Livewire-driven, so the markup you restyle must keep its bindings. A theme may ship plain markup instead of <x-theme.*> components, but it may never drop a wire: attribute.
Actually submit each interactive surface and confirm it works end to end:
- Login / register / password reset — submit with bad input (see validation errors render) and good input (see it proceed). Confirm
wire:submit, everywire:modelon the inputs, and anywire:clickon buttons are intact. - Contact form — submit and confirm the success state.
- Product order — change a cycle, add to cart; confirm the mini-cart updates live.
- Domain search — run a search and see results populate.
- Cart & checkout — adjust quantities, proceed to checkout, reach confirmation.
If a form silently does nothing, open the browser console and network tab: a missing wire:model means the component never sees the field; a missing wire:submit means the browser does a full-page GET instead of a Livewire round-trip. Preserving these bindings is the whole contract of restyling an auth or order page — see Authentication pages and Components.
The fallback story#
Understand exactly what Core does when a view is missing, because it decides how your bugs surface.
- When NO theme is installed at all, every
themes.*view resolves to a neutral Core holding page viaApp\View\ThemeFallbackViewFinder. This is the first-run path, not an error. - When your theme IS installed but is missing a view, resolution throws. There is no cross-fallback to another theme — Core ships none to fall back to. The finder does this deliberately: substituting a full "no theme installed" page into a layout slot for a missing partial would hide the bug and call it success.
So during testing, a "View not found: themes.your-theme.cart.checkout" exception is Core telling you your theme is incomplete. The fix is never to suppress it — it is to ship the view. The one nuance: <x-theme.*> components you omit fall back to Core base components under resources/views/components/theme/ (registered in AppServiceProvider), so a missing component primitive renders rather than throws. That fallback is for components only, never for pages, sections, layouts, or auth/error views.
The practical test: with your theme active, walk the entire checklist above. If nothing throws, you have shipped every view. If something throws, you found the gap before a customer did.
Common pitfalls#
These are the traps that pass a glance and fail in production. Check for each one.
1. The `@lang`-array-with-nested-calls trap. Passing an array of replacements to @lang() or __() where a value is itself a Blade/PHP call can break parsing or emit the wrong string. Keep translation calls flat — resolve any dynamic value into a plain variable first, then pass it as a simple replacement:
{{-- Fragile: a nested call inside the replacements array --}}
@lang('Welcome, :name', ['name' => auth()->user()->fullName()])
{{-- Robust: resolve first, pass a scalar --}}
@php $name = auth()->user()->fullName(); @endphp
{{ __('Welcome, :name', ['name' => $name]) }}2. Blade directives inside component tags. A control-flow directive placed inside a <x-...> tag's attribute list silently corrupts the component — it does not render an error, it renders wrong. Put the directive around the tag, never inside it:
{{-- Broken: @if lives inside the component tag --}}
<x-theme.btn-primary @if($featured) class="ring-2" @endif>Buy</x-theme.btn-primary>
{{-- Correct: conditionals wrap the tag, or feed a prebuilt value --}}
@php $ring = $featured ? 'ring-2' : ''; @endphp
<x-theme.btn-primary class="{{ $ring }}">Buy</x-theme.btn-primary>3. An unlayered `<style>` block beating your utilities. A plain <style> block in a view emits at a higher effective specificity/order than your utility layer, so a single rule there silently overrides utility classes across the page. In bundled themes keep custom CSS inside the proper layer; in a precompiled uploaded theme, keep styling in your compiled assets/css/*.css file and reference it via themeAsset('css/theme.css') rather than inlining a stray <style> block that outranks everything.
4. Broken `@include` paths. Section and partial includes must go through the theme-aware helpers, not a hardcoded prefix. Use activeTemplate().'partials.render-sections' and templateViewName('sections.'.$slug) (the render loop is tolerant — a missing section slug is skipped, not fatal), but a typo'd literal path either throws or silently renders nothing. Confirm every custom @include/@includeIf resolves. See Building sections.
5. iOS auto-zoom on small inputs. Mobile Safari zooms the viewport whenever a focused input has a font-size under 16px, and it does not zoom back out — the most likely place to hit it is a login form. Give inputs a 16px minimum on mobile and drop to your smaller desktop size at a breakpoint:
/* iOS never zooms a control that is >= 16px on focus */
.form-input {
font-size: 16px;
}
@media (min-width: 640px) {
.form-input {
font-size: 14px;
}
}6. Forgetting to precompile CSS. Uploaded themes ship precompiled plain CSS/JS — there is no @vite, no @tailwind, and no @apply at runtime. If you develop against a bundled build and forget to compile your final stylesheet into assets/css/, the live theme loads a file that references utilities that were never emitted, and the whole page renders unstyled. Compile, publish assets, hard-refresh, and confirm the page is actually styled from public/assets/themes/{name}/ before you package. Details in CSS, JavaScript & images.
Ship checklist#
Before you cut a version, confirm all of:
- [ ] Every view in the completeness checklist renders — nothing throws with your theme active
- [ ] Light and dark both clean on every distinct surface
- [ ] No horizontal scroll at 375px; dense tables scroll inside their own container
- [ ] Every form submits (Livewire
wire:bindings intact) - [ ] All 6 error pages and all 8 auth pages open
- [ ] CSS/JS precompiled into
assets/and published; page renders styled frompublic/ - [ ]
theme.jsonandsalieno.jsonversions match
Next: once your theme passes this routine, go to Publishing & updating on the marketplace to version, sign, and ship it — including how updates swap files only and never touch a customer's page-builder content.