nowo-tech/slide-to-confirm-bundle
A Symfony bundle that adds a slide-to-confirm control for sensitive actions, helping prevent accidental clicks and submissions. Drop it into forms or templates with customizable labels, styling, and behavior for a safer, smoother confirmation flow.
Install the bundle (Composer):
composer require nowo-tech/slide-to-confirm-bundle
Symfony Flex auto-registers the bundle in config/bundles.php; on a legacy setup add Nowo\SlideToConfirmBundle\SlideToConfirmBundle manually.
Publish the frontend assets (if the bundle ships a build, per its Vite strategy):
php bin/console assets:install public
Do not edit anything under src/Resources/public/build in vendor — it’s generated.
Wire the Twig form theme. The widget is almost certainly a customized Twig block, so register the bundle’s form theme in config/packages/twig.yaml:
twig:
form_themes:
- '@SlideToConfirm/form/slide_to_confirm_layout.html.twig'
First use case — confirm a destructive action. In a Symfony form, add the field as a typed field rather than a generic checkbox:
use Nowo\SlideToConfirmBundle\Form\Type\SlideToConfirmType;
$builder->add('confirmDelete', SlideToConfirmType::class, [
'label' => 'Slide to confirm deletion',
'confirm_text' => 'Delete',
]);
Render and submit in Twig as any other field:
{{ form_start(form) }}
{{ form_row(form.confirmDelete) }}
<button type="submit">Submit</button>
{{ form_end(form) }}
The first thing to inspect after install: the bundle’s Form/Type/SlideToConfirmType.php (available options and constraints) and the Twig form theme template — those two files define the whole day-to-day experience.
Use it as a gate, not a validator. The slide confirm is a UX-level “I really mean it” signal. Pair it with a NotBlank/custom constraint so a forged or absent submitted value fails server-side:
$builder->add('confirmDelete', SlideToConfirmType::class, [
'constraints' => [new NotBlank(['message' => 'Please slide to confirm.'])],
]);
One form type per intent. Rather than reusing the same SlideToConfirmType field with different labels for payments, deletes, and legal consent, declare dedicated wrapper types (DeleteConfirmType, PaymentConfirmType, LegalConsentType) that extend or reuse the base type. This keeps options consistent and lets you swap templates later without touching every form.
Server-side check against the submitted value. When the form is submitted, validate that the field value matches the expected token/label. Never rely on the fact that the widget rendered — treat the submitted value as untrusted.
Multi-instance pages. If a page renders several slide widgets (e.g. a list of delete buttons), initialize per element. Symfony’s JS entrypoint usually scopes to a data-* attribute; verify the bundle’s initialization targets instances, not a global singleton.
Customize via options first, template override second. Set label, confirm_text, and any visual options from PHP. Reserve Twig block overrides (e.g. slide_to_confirm_widget) for structural changes — the bundle follows a “preserve current block structure” rule, so overrides are usually safe.
Integrate with Turbo / Hotwire / htmx. After a Turbo frame replacement the widget’s JS listeners are reattached only if the bundle hooks into Turbo’s lifecycle (turbo:load, turbo:frame-load) or if it initializes lazily. If the widget goes dead after navigation, this is the first place to check.
Styling. Import the bundle’s CSS through your existing Vite/asset entry rather than adding <link> tags per page — it keeps the build pipeline the single source of truth.
Legal consent. Model it as a real field on your form and persist it (with timestamp + user id) like any other accepted consent — the slide is the UI, the persisted record is the evidence.
The slide value is client-side. Anyone can POST confirmDelete=1 without sliding. Always require a matching server-side constraint or a signed token in the form. The bundle gives UX, not security.
Accessibility. Slide gestures are unusable for keyboard-only and screen-reader users. Check whether the bundle renders a fallback (checkbox / hidden input driven by keyboard). If not, provide one in your form theme override and gate the JS widget behind prefers-reduced-motion / pointer: fine.
Assets not installed. The most common “widget doesn’t render” issue is a missing assets:install or a stale Vite build after upgrading the bundle. Re-run assets:install and clear the Symfony cache before debugging JS.
Form theme not registered. The field will render as an unstyled hidden input if form_themes doesn’t include the bundle’s template. Look for slide_to_confirm_layout.html.twig (or similar) in @SlideToConfirm and add it to twig.form_themes.
Cache in dev after option changes. Bundle Twig/asset caches survive cache:clear less reliably than you’d expect; if option changes don’t appear, delete var/cache/dev once.
Don’t fork the build output. Per the repo’s rules, src/Resources/public/build is generated. If you need styling changes, extend CSS in your own app stylesheet or override Twig blocks — never patch the built JS/CSS in vendor.
Debugging a stuck widget. Check in order: (1) is the form theme registered, (2) did the JS entrypoint load (network tab), (3) is the element initialized (look for a data attribute or class the JS adds on boot), (4) did a Turbo/htmx navigation replace the element without re-initialization.
Extension points. The bundle is designed to be extended — subclass SlideToConfirmType for domain-specific options (e.g. currency, payment_reference), and override the Twig *_widget block for layout. Keep public service IDs and option names as-is to stay upgrade-safe.
How can I help you explore Laravel packages today?