Inertia Modal Development
Overview
Use inertiaui/modal to open any Laravel route in a Modal or Slideover without modifying existing routes or controllers. Works with both React and Vue, supports nested modals, prefetching, local modals, headless mode, and TypeScript.
When to Activate
- Activate when working with modals or slideovers in a Laravel + Inertia.js application.
- Activate when code references
ModalLink,Modal,HeadlessModal,ModalRoot,useModal,useModalStack,visitModal, orInertia::modal(). - Activate when the user wants to open a route in a modal, configure modal behavior, use prefetching, set up nested modals, or communicate between modals.
- Activate when imports reference
@inertiaui/modal-vueor@inertiaui/modal-react.
Scope
- In scope: modal routes, ModalLink, Modal component, configuration, prefetching, local modals, nested modals, event bus, reload props, deferred props, headless mode, base route/URL, styling.
- Out of scope: general Inertia.js routing without modals, non-Laravel backends.
Workflow
- Identify the task (opening a modal, configuring behavior, setting up communication, etc.).
- Read
references/inertia-modal-guide.mdand focus on the relevant section. - Apply the patterns from the reference, using the correct framework (React or Vue).
Core Concepts
Backend: Opening a Route as a Modal
Use Inertia::modal() instead of Inertia::render() in your controller:
return Inertia::modal('EditUser', [
'user' => $user,
'roles' => Role::pluck('name', 'id'),
]);
With a base route (enables URL changes and browser history):
return Inertia::modal('EditUser', ['user' => $user])
->baseRoute('users.index');
Frontend: App Setup
Use renderApp in your app.js/app.jsx:
// Vue
import { renderApp } from '@inertiaui/modal-vue'
createInertiaApp({
setup({ el, App, props, plugin }) {
createApp({ render: renderApp(App, props) })
.use(plugin)
.mount(el)
}
})
// React
import { renderApp } from '@inertiaui/modal-react'
createInertiaApp({
setup({ el, App, props }) {
const root = createRoot(el);
root.render(renderApp(App, props));
}
});
Frontend: ModalLink Component
<!-- Vue -->
<ModalLink href="/users/create">Create User</ModalLink>
// React
<ModalLink href="/users/create">Create User</ModalLink>
Frontend: Modal Component
<!-- Vue -->
<Modal>
<h1>Create User</h1>
<form><!-- ... --></form>
</Modal>
// React
<Modal>
<h1>Create User</h1>
<form>{/* ... */}</form>
</Modal>
Programmatic Usage
// Vue
import { visitModal } from '@inertiaui/modal-vue'
visitModal('/users/create')
// React
const { visitModal } = useModalStack()
visitModal('/users/create')
Configuration
import { putConfig } from '@inertiaui/modal-vue' // or modal-react
putConfig({
type: 'modal',
navigate: false,
useNativeDialog: true,
appElement: '#app',
modal: {
closeButton: true,
closeExplicitly: false,
closeOnClickOutside: true,
maxWidth: '2xl',
paddingClasses: 'p-4 sm:p-6',
panelClasses: 'bg-white rounded',
position: 'center',
},
slideover: {
closeButton: true,
closeExplicitly: false,
closeOnClickOutside: true,
maxWidth: 'md',
paddingClasses: 'p-4 sm:p-6',
panelClasses: 'bg-white min-h-screen',
position: 'right',
},
})
Do and Don't
Do:
- Always use
Inertia::modal()(notInertia::render()) when opening routes as modals. - Always call
renderAppor set upModalRoot/ModalStackProviderin your app entry point. - Use the
navigateprop onModalLink(or global config) when you want URL changes and browser history. - Use
closeOnClickOutsideto disable only backdrop clicks; usecloseExplicitlyto disable both backdrop clicks and Esc key. - Use Axios for form submissions in nested modals to avoid closing the entire stack.
- Import
DeferredandWhenVisiblefrom the modal package (not Inertia) when used inside modals.
Don't:
- Don't forget to set up the
renderApphelper orModalRootcomponent — modals won't work without it. - Don't use
Inertia::render()for modal routes — useInertia::modal(). - Don't use
router.post()(Inertia router) in nested modals — it navigates to the base route and closes all modals. Use Axios instead. - Don't import
DeferredorWhenVisiblefrom@inertiajs/vue3or@inertiajs/reactwhen inside a modal — use the modal package's versions. - Don't reference conversion names in
closeOnClickOutsideandcloseExplicitlytogether —closeExplicitlysupersedescloseOnClickOutside.
References
references/inertia-modal-guide.md