← Back to all work
Convert UK vehicle scrappage and valuation service

A quote-step redesign, shipped client-side on a React funnel

A full redesign of the Vehicle Details step in an online quote funnel, delivered entirely client-side through Convert on a React single-page application, with no access to the codebase. Built to survive React re-renders and to read the visitor's own vehicle data live.

The existing two-column Vehicle Details step, with an offer sidebar on the left and a three-step progress indicator above the form
Control: a two-column layout with the offer in a sidebar and a three-step progress bar.

The problem

A UK vehicle scrappage and valuation service runs a multi-step online quote funnel. A visitor enters a registration, receives an indicative offer, then works through a series of steps to confirm the vehicle's condition and their own details before the lead is submitted. The step under test is the Vehicle Details screen, where the visitor answers questions about the engine, gearbox, write-off status, warning lights, crash damage and interior condition.

The existing layout splits the screen into two columns. A left sidebar holds the offer, the vehicle, the registration plate and the headline value, and a right column holds the form, topped by a three-step progress indicator. The page is a working conversion mechanism, so any change carries real revenue sensitivity.

The brief was to test a cleaner, single-column version of this step, with the offer moved into a prominent banner and the condition questions made easier to answer at a glance.

The hypothesis

A simpler, less cluttered Vehicle Details step, with the offer value kept visible and the condition questions made more self-explanatory, will hold a visitor's attention through the step and improve progression toward a completed lead.

Two decisions here are real bets rather than cosmetic tidying. The offer value moves from a persistent sidebar to a banner across the top, so it stays visible but changes in prominence, and on this site that number is the main motivator. The three-step progress indicator is removed. Progress indicators usually help completion, so taking it out is a deliberate, testable choice, not a side effect of the cleaner layout.

The solution

The variation keeps the same six questions, the same answer options and the same underlying form logic as the control. Only the presentation changes:

  • The two-column layout becomes a single centred card, and the offer sidebar is hidden.
  • A banner across the top shows the headline value, the vehicle, the registration plate and a "this is not my vehicle" link, populated live from the visitor's own data.
  • The three-step progress indicator is suppressed.
  • The answer buttons are enlarged, with a clearer selected state.
  • For the first two questions, the explanatory copy that previously sat behind a tooltip is shown inline inside each button, so the visitor does not have to open a tooltip to understand the options.
  • The submit button is restyled and its label changes from "Next" to "Get Best Price".
The single-column variation with the offer in a top banner, larger answer buttons, inline descriptions on the first two questions, and a restyled call to action
Variation: single column, the offer in a top banner, inline descriptions, and a restyled CTA.

Implementation

The redesign had to be delivered entirely client-side through Convert, with no access to the site's codebase. The page is a React single-page application, which sets two traps for client-side testing. React re-renders parts of the form on every interaction, so a change made once on load gets undone the moment a visitor selects an answer. And the form's input state is owned by React, so reading values straight from the DOM or setting them directly is unreliable.

The method was to re-skin, not rebuild. Rather than deleting and reconstructing the form, which fights React's reconciliation and causes visible flicker, the variation keeps React's actual form intact and changes only its presentation. The split is deliberate: CSS does as much of the work as it can, and JavaScript is reserved for the short list of things CSS cannot do.

// Folder structure

experiment/
  src/
    lib/
      components/
        banner.js
      helpers/
        vehicle-data.js
    experiment.js
    experiment.scss
    triggers.js

CSS does the bulk, so it survives re-renders for free

Layout, hiding the sidebar and the progress bar, restyling the buttons and injecting the inline question descriptions are all done in CSS, scoped under a single class on the page's root element. CSS rules reapply on every render at no cost, so they survive React re-renders with no extra handling. The inline descriptions are added with a ::after rule rather than a DOM edit, so React never sees a change to react to.

// Presentation in CSS, scoped under one root class

.exp .grid > div:first-child { display: none; }   /* hide the offer sidebar */
.exp .progress-steps { display: none; }            /* hide the 3-step indicator */

.exp form input[type="radio"]:checked + label {
  background: #fff;
  border: 2px solid #143083;
  color: #143083;
}

/* Inject the description with CSS, so there is no DOM change to undo */
.exp input[name="engine_condition"][value="1"] + label::after {
  content: "Engine that starts and runs as intended";
  display: block;
}

Re-applying across the funnel, without a done flag

The step sits inside a multi-step funnel, so the visitor moves between steps without a full page load. The variation applies once the form has mounted, then on every route change it resets and re-applies. The reset is the clean part: removing the single scope class from the root element reverts every CSS-driven change at once, which leaves only the injected banner to remove. Each JavaScript change is idempotent on its own, so the CTA is relabelled only when it has not been already, the icon swap guards on its own marker, and the banner inserts only when absent. Because the reset and those guards do the work, there is no need for a "done" flag on the DOM.

// Reset reverts every CSS change in one line, then drops the banner

const resetUi = () => {
  document.documentElement.classList.remove(ID, `${ID}-${VARIATION}`);
  document.querySelector(`[data-exp-banner="${ID}"]`)?.remove();
};

// Apply on mount, then reset and re-apply on each route change

waitFor(".quote-form", () => {
  apply();
  onUrlChange(() => {
    resetUi();
    apply();
  });
});

Reading the vehicle data robustly

The banner is populated from the browser's localStorage rather than scraped from the now hidden sidebar. The storage key is derived from a parameter in the page URL that keys directly to the stored form object. Reading from storage means the banner does not depend on the sidebar having rendered, and it survives the sidebar being hidden. The read is wrapped defensively, so if the data is missing the banner simply does not render rather than showing an empty value.

// Read the vehicle from storage, never throw into the page

const getVehicleData = () => {
  try {
    const qfi = new URLSearchParams(location.search).get("qfi");
    if (!qfi) return null;
    const raw = localStorage.getItem(`form_${qfi}`);
    if (!raw) return null;
    const data = JSON.parse(raw);
    const v = data.vehicleDetails ?? {};
    return {
      make: v.vehicleMake ?? "",
      model: v.vehicleModel ?? "",
      year: v.vehicleYear ?? "",
      reg: v.vehicleRegistration ?? "",
      uptoPrice: data.upto_price ?? "",
    };
  } catch {
    return null; // never throw into the page
  }
};

Success metrics

Primary metric: completed lead submission through the full funnel, not the first click. A cleaner first screen can lift first-step engagement while hurting overall completion, or the reverse, so the headline has to be end-to-end completion rather than clicks on "Get Best Price". The step-level metric is progression from the Vehicle Details step to the next step. Because the variation removes the progress indicator and changes the prominence of the offer value, the guardrail is any negative effect on completion that a cleaner layout might otherwise mask.

Post-test analysis

The experiment has been built and is in QA. Results are pending. This section will be updated with anonymised outcome highlights once the test has run and the analysis is complete.

← Back to all work