Styling and localization
Translate popover labels and restyle Driver.js popovers and Hints.
Every visible string Driver.js renders comes from an option UX Driver serializes, so translation happens in Twig with the rest of the page — no JavaScript locale bundle.
Text
Tours and Steps both accept the four label options. Set them on the Tour for the whole walkthrough, or on one Step to override it there:
Component
<twig:Driver:Tour
id="checkout-tour"
progressText="{{ '{{current}}' }} / {{ '{{total}}' }}"
nextBtnText="{{ 'tour.next'|trans }}"
prevBtnText="{{ 'tour.back'|trans }}"
doneBtnText="{{ 'tour.done'|trans }}"
>
...
</twig:Driver:Tour>Twig builder
{% set tour = create_tour('checkout-tour')
.progressText('{{current}} / {{total}}')
.nextBtnText('tour.next'|trans)
.prevBtnText('tour.back'|trans)
.doneBtnText('tour.done'|trans) %}PHP builder
use Symfony\Contracts\Translation\TranslatorInterface;
public function checkout(TranslatorInterface $translator): Response
{
$tour = $this->tourBuilder->create('checkout-tour')
->progressText('{{current}} / {{total}}')
->nextBtnText($translator->trans('tour.next'))
->prevBtnText($translator->trans('tour.back'))
->doneBtnText($translator->trans('tour.done'));
return $this->render('checkout/index.html.twig', ['tour' => $tour]);
}In PHP the {{current}} and {{total}} placeholders need no escaping dance — Twig never sees them.
progressText is a Driver.js template: {{ '{{current}}' }} and {{ '{{total}}' }} are substituted at
render time. In a component prop the braces have to be escaped so Twig does not claim them first; inside a
builder call they sit in a quoted string, where Twig leaves them alone.
Hints use a single buttonText:
Component
<twig:Driver:Hints id="checkout-help" buttonText="{{ 'hints.done'|trans }}">
...
</twig:Driver:Hints>Twig builder
{% set hints = create_hints('checkout-help').buttonText('hints.done'|trans) %}PHP builder
$hints = $this->hintsBuilder->create('checkout-help')
->buttonText($translator->trans('hints.done'));Popover CSS
popoverClass adds a class to the popover wrapper, on the Tour or on a single Step:
Component
<twig:Driver:Tour id="checkout-tour" popoverClass="checkout-popover">
...
</twig:Driver:Tour>Twig builder
{% set tour = create_tour('checkout-tour').popoverClass('checkout-popover') %}PHP builder
$tour = $this->tourBuilder->create('checkout-tour')
->popoverClass('checkout-popover');The popover’s four arrow variants are colored borders on a pseudo-element, one per side. A custom variable keeps them in sync with the popover background:
.driver-popover.checkout-popover {
--popover-bg: #111827;
background-color: var(--popover-bg);
color: #f9fafb;
}
.checkout-popover .driver-popover-title {
color: #ffffff;
}
.checkout-popover .driver-popover-description,
.checkout-popover .driver-popover-progress-text {
color: #d1d5db;
}
.checkout-popover .driver-popover-footer-btn {
background-color: #f9fafb;
color: var(--popover-bg);
}
.checkout-popover .driver-popover-arrow-side-top { border-top-color: var(--popover-bg) }
.checkout-popover .driver-popover-arrow-side-right { border-right-color: var(--popover-bg) }
.checkout-popover .driver-popover-arrow-side-bottom { border-bottom-color: var(--popover-bg) }
.checkout-popover .driver-popover-arrow-side-left { border-left-color: var(--popover-bg) }
The class surface
Driver.js 1.8 exposes --driver-popover-font-family as its only popover custom property. Everything else
is a class: .driver-popover, .driver-popover-title, .driver-popover-description,
.driver-popover-footer, .driver-popover-progress-text, .driver-popover-footer-btn,
.driver-popover-arrow, .driver-overlay, and .driver-active-element.
Hints add .driver-hint, .driver-hint-dot, .driver-hint-pulse, .driver-hint-popover, and
.driver-hint-overlay, and their stylesheet is variable-driven:
| Variable | Controls |
|---|---|
--driver-hint-size | Beacon diameter |
--driver-hint-color | Beacon and pulse color |
--driver-hint-animation-duration | Pulse cycle length |
.driver-hint {
--driver-hint-color: #e23845;
--driver-hint-size: 14px;
}
Motion
:animate="false" turns off the Driver.js transition between Steps. The bundle does not read
prefers-reduced-motion for you — if that matters, decide it in the template:
Component
<twig:Driver:Tour id="checkout-tour" :animate="animate ?? true">Twig builder
{% set tour = create_tour('checkout-tour').animate(animate ?? true) %}PHP builder
$tour = $this->tourBuilder->create('checkout-tour')
->animate($userPrefersMotion);Beyond motion: keep titles short, make button labels say what happens, and do not let color carry meaning on its own in a custom theme.