xi/dialog-bundle
Xi Dialog Bundle provides reusable dialog and modal components for PHP applications, with simple configuration and integration for handling user interactions. It offers a lightweight way to add maintainable dialog workflows to your project without unnecessary overhead.
Install the bundle (and its AJAX dependency) via Composer:
composer require xi/dialog-bundle xi/ajax-bundle
Register both bundles in app/AppKernel.php (Symfony 2/3 era) — order matters, dialog depends on ajax:
new Xi\Bundle\AjaxBundle\XiAjaxBundle(),
new Xi\Bundle\DialogBundle\XiDialogBundle(),
Install the public assets so the jQuery dialog scripts are reachable from your layout:
php app/console assets:install --symlink
Look first at Resources/public/js/ and Resources/views/ inside the bundle to see the exact JS initializer and any provided Twig helpers — this bundle is small enough that the source is the documentation. Also check DependencyInjection/Configuration.php for the handful of configurable defaults (typically modal, title, width/height, and which selector triggers a dialog).
Include jQuery plus the bundle's script in your base layout, after jQuery:
<script src="{{ asset('bundles/xidialog/js/dialog.js') }}"></script>
First use case: turn an ordinary anchor into an AJAX-loaded modal. Mark the link with whatever data-* contract the bundle's JS expects (commonly data-dialog="true" plus href as the endpoint), point the href at a controller action that returns just the dialog body HTML, and the bundle's initializer will fetch that fragment and open it in a jQuery UI dialog. That is the whole point of the package: a thin convention for "click a link, load a fragment, show it modally."
Action-as-fragment. The cleanest pattern is to keep dialog endpoints returning bare HTML (no layout). Use a dedicated controller or a _dialog request attribute:
public function editAction(Request $request, $id)
{
$form = $this->createForm(EditType::class, $entity);
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
// persist...
return $this->render('AppBundle:Dialog:success.html.twig');
}
return $this->render('AppBundle:Dialog:edit.html.twig', ['form' => $form->createView()]);
}
On success, return a small fragment (a message or an empty response) that the bundle's JS can use to close the dialog; on validation failure, return the re-rendered form so the user stays in the modal.
Link-triggered dialogs in Twig. Wrap the trigger in a helper or plain markup:
<a href="{{ path('app_entity_edit', {id: entity.id}) }}"
class="xi-dialog"
data-dialog-title="Edit {{ entity.name }}">Edit</a>
Keeping the trigger as a real href means the endpoint still works as a fallback page if JS is disabled or the dialog fails to open.
Form posts inside the dialog. Because the AJAX bundle intercepts submissions, submit the form normally from the user's perspective — the bundle swaps the dialog content with the response. This is the primary workflow for create/edit/delete confirmations and is where the package earns its keep: you write ordinary Symfony form controllers and get modal UX for free.
Delete confirmations. A read-only GET action returning a "Are you sure?" fragment, with a POST form inside that deletes and returns a close trigger, is the lowest-risk integration and avoids half-submitted state in a modal.
Composing with xi/ajax-bundle directly. If you need behavior the dialog wrapper doesn't expose (e.g. loading a second fragment into the same dialog), drop to the ajax-bundle API — the dialog bundle is essentially a preset of it. Treat the dialog layer as sugar and the ajax layer as the actual transport.
Centralize dialog defaults. Set global options once (modal, resizable, width) in your bundle config or a small JS file loaded after the bundle script, then override per-link with data attributes. Avoid scattering inline $(...).dialog({...}) calls across templates.
assets:install wasn't run, or the script tag points at the wrong bundles/xidialog/... path. Verify the file exists under web/bundles/ before debugging anything else._fragment layout that only outputs the body content.data-* options the JS reads — read the shipped JS to confirm exact attribute names before assuming data-dialog-* conventions. Typos fail silently (the link just navigates normally).Resources/public/js/*.js and the DI extension first; there is no upstream issue tracker worth relying on.How can I help you explore Laravel packages today?