|
| 1 | +# Inertia Modal |
| 2 | + |
| 3 | +[Inertia Modal](https://github.com/inertiaui/modal) is a powerful library that enables you to render any Inertia page |
| 4 | +as a modal dialog. It seamlessly integrates with your existing Inertia.js application, allowing you to create modal |
| 5 | +workflows without the complexity of managing modal state manually. |
| 6 | + |
| 7 | +Here's a summary of the features: |
| 8 | + |
| 9 | +- Supports React and Vue |
| 10 | +- Zero backend configuration |
| 11 | +- Super simple frontend API |
| 12 | +- Support for Base Route / URL |
| 13 | +- Modal and slideover support |
| 14 | +- Headless support |
| 15 | +- Nested/stacked modals support |
| 16 | +- Reusable modals |
| 17 | +- Multiple sizes and positions |
| 18 | +- Reload props in modals |
| 19 | +- Easy communication between nested/stacked modals |
| 20 | +- Highly configurable |
| 21 | + |
| 22 | +While you can use Inertia Modal without changes on the backend, we recommend using the Rails gem |
| 23 | +[`inertia_rails-contrib`](https://github.com/skryukov/inertia_rails-contrib) to enhance your modals with base URL support. This ensures that your modals are accessible, |
| 24 | +SEO-friendly, and provide a better user experience. |
| 25 | + |
| 26 | +> [!NOTE] |
| 27 | +> Svelte 5 is not yet supported by Inertia Modal. |
| 28 | +
|
| 29 | +## Installation |
| 30 | + |
| 31 | +### 1. Install the NPM Package |
| 32 | + |
| 33 | +:::tabs key:frameworks |
| 34 | +== Vue |
| 35 | + |
| 36 | +```bash |
| 37 | +npm install @inertiaui/modal-vue |
| 38 | +``` |
| 39 | + |
| 40 | +== React |
| 41 | + |
| 42 | +```bash |
| 43 | +npm install @inertiaui/modal-react |
| 44 | +``` |
| 45 | + |
| 46 | +::: |
| 47 | + |
| 48 | +### 2. Configure Inertia |
| 49 | + |
| 50 | +Update your Inertia app setup to include the modal plugin: |
| 51 | + |
| 52 | +:::tabs key:frameworks |
| 53 | +== Vue |
| 54 | + |
| 55 | +```js |
| 56 | +// frontend/entrypoints/inertia.js |
| 57 | +import { createApp, h } from 'vue' |
| 58 | +import { createInertiaApp } from '@inertiajs/vue3' |
| 59 | +import { renderApp } from '@inertiaui/modal-vue' // [!code ++] |
| 60 | + |
| 61 | +createInertiaApp({ |
| 62 | + resolve: (name) => { |
| 63 | + const pages = import.meta.glob('../pages/**/*.vue', { eager: true }) |
| 64 | + return pages[`../pages/${name}.vue`] |
| 65 | + }, |
| 66 | + setup({ el, App, props, plugin }) { |
| 67 | + createApp({ render: () => h(App, props) }) // [!code --] |
| 68 | + createApp({ render: renderApp(App, props) }) // [!code ++] |
| 69 | + .use(plugin) |
| 70 | + .mount(el) |
| 71 | + }, |
| 72 | +}) |
| 73 | +``` |
| 74 | + |
| 75 | +== React |
| 76 | + |
| 77 | +```js |
| 78 | +// frontend/entrypoints/inertia.js |
| 79 | +import { createInertiaApp } from '@inertiajs/react' |
| 80 | +import { createElement } from 'react' // [!code --] |
| 81 | +import { renderApp } from '@inertiaui/modal-react' // [!code ++] |
| 82 | +import { createRoot } from 'react-dom/client' |
| 83 | + |
| 84 | +createInertiaApp({ |
| 85 | + resolve: (name) => { |
| 86 | + const pages = import.meta.glob('../pages/**/*.jsx', { eager: true }) |
| 87 | + return pages[`../pages/${name}.jsx`] |
| 88 | + }, |
| 89 | + setup({ el, App, props }) { |
| 90 | + const root = createRoot(el) |
| 91 | + root.render(createElement(App, props)) // [!code --] |
| 92 | + root.render(renderApp(App, props)) // [!code ++] |
| 93 | + }, |
| 94 | +}) |
| 95 | +``` |
| 96 | + |
| 97 | +::: |
| 98 | + |
| 99 | +### 3. Tailwind CSS Configuration |
| 100 | + |
| 101 | +:::tabs key:frameworks |
| 102 | +== Vue |
| 103 | + |
| 104 | +For Tailwind CSS v4, add the modal styles to your CSS: |
| 105 | + |
| 106 | +```css |
| 107 | +/* app/entrypoints/frontend/application.css */ |
| 108 | +@source "../../../node_modules/@inertiaui/modal-vue"; |
| 109 | +``` |
| 110 | + |
| 111 | +For Tailwind CSS v3, update your `tailwind.config.js`: |
| 112 | + |
| 113 | +```js |
| 114 | +export default { |
| 115 | + content: [ |
| 116 | + './node_modules/@inertiaui/modal-vue/src/**/*.{js,vue}', |
| 117 | + // other paths... |
| 118 | + ], |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +== React |
| 123 | + |
| 124 | +For Tailwind CSS v4, add the modal styles to your CSS: |
| 125 | + |
| 126 | +```css |
| 127 | +/* app/entrypoints/frontend/application.css */ |
| 128 | +@source "../../../node_modules/@inertiaui/modal-react"; |
| 129 | +``` |
| 130 | + |
| 131 | +For Tailwind CSS v3, update your `tailwind.config.js`: |
| 132 | + |
| 133 | +```js |
| 134 | +export default { |
| 135 | + content: [ |
| 136 | + './node_modules/@inertiaui/modal-react/src/**/*.{js,jsx}', |
| 137 | + // other paths... |
| 138 | + ], |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +::: |
| 143 | + |
| 144 | +### 4. Add the Ruby Gem (optional but recommended) |
| 145 | + |
| 146 | +Install the [`inertia_rails-contrib`](https://github.com/skryukov/inertia_rails-contrib) gem to your Rails application to enable base URL support for modals: |
| 147 | + |
| 148 | +```bash |
| 149 | +bundle add inertia_rails-contrib |
| 150 | +``` |
| 151 | + |
| 152 | +## Basic example |
| 153 | + |
| 154 | +The package comes with two components: `Modal` and `ModalLink`. `ModalLink` is very similar to Inertia's [built-in |
| 155 | +`Link` component](/guide/links), but it opens the linked route in a modal instead of a full page load. So, if you have a |
| 156 | +link that you want to open in a modal, you can simply replace `Link` with `ModalLink`. |
| 157 | + |
| 158 | +:::tabs key:frameworks |
| 159 | +== Vue |
| 160 | + |
| 161 | +```vue |
| 162 | +<script setup> |
| 163 | +import { Link } from '@inertiajs/vue3' // [!code --] |
| 164 | +import { ModalLink } from '@inertiaui/modal-vue' // [!code ++] |
| 165 | +</script> |
| 166 | +
|
| 167 | +<template> |
| 168 | + <!-- [!code --] --> |
| 169 | + <Link href="/users/create">Create User</Link> |
| 170 | + <!-- [!code ++] --> |
| 171 | + <ModalLink href="/users/create">Create User</ModalLink> |
| 172 | +</template> |
| 173 | +``` |
| 174 | + |
| 175 | +== React |
| 176 | + |
| 177 | +```jsx |
| 178 | +import {Link} from '@inertiajs/react' // [!code --] |
| 179 | +import {ModalLink} from '@inertiaui/modal-react' // [!code ++] |
| 180 | + |
| 181 | +export const CreateUserButton = () => { |
| 182 | + return ( |
| 183 | + <Link href="/users/create">Create User</Link> // [!code --] |
| 184 | + <ModalLink href="/users/create">Create User</ModalLink> // [!code ++] |
| 185 | + ) |
| 186 | +} |
| 187 | +``` |
| 188 | + |
| 189 | +::: |
| 190 | + |
| 191 | +The page you linked can then use the `Modal` component to wrap its content in a modal. |
| 192 | + |
| 193 | +:::tabs key:frameworks |
| 194 | +== Vue |
| 195 | + |
| 196 | +```vue |
| 197 | +<script setup> |
| 198 | +import { Modal } from '@inertiaui/modal-vue' |
| 199 | +</script> |
| 200 | +
|
| 201 | +<template> |
| 202 | + <!-- [!code ++] --> |
| 203 | + <Modal> |
| 204 | + <h1>Create User</h1> |
| 205 | + <form> |
| 206 | + <!-- Form fields --> |
| 207 | + </form> |
| 208 | + <!-- [!code ++] --> |
| 209 | + </Modal> |
| 210 | +</template> |
| 211 | +``` |
| 212 | + |
| 213 | +== React |
| 214 | + |
| 215 | +```jsx |
| 216 | +import {Modal} from '@inertiaui/modal-react' |
| 217 | + |
| 218 | +export const CreateUser = () => { |
| 219 | + return ( |
| 220 | + {/* [!code --] */} |
| 221 | + <> |
| 222 | + {/* [!code ++] */} |
| 223 | + <Modal> |
| 224 | + <h1>Create User</h1> |
| 225 | + <form> |
| 226 | + {/* Form fields */} |
| 227 | + </form> |
| 228 | + {/* [!code --] */} |
| 229 | + </Modal> |
| 230 | + {/* [!code ++] */} |
| 231 | + </> |
| 232 | + ) |
| 233 | +} |
| 234 | +``` |
| 235 | + |
| 236 | +::: |
| 237 | + |
| 238 | +That's it! There is no need to change anything about your routes or controllers! |
| 239 | + |
| 240 | +## Enhanced Usage With Base URL Support |
| 241 | + |
| 242 | +By default, Inertia Modal doesn't change the URL when opening a modal. It just stays on the same page and displays the |
| 243 | +modal content. However, you may want to change this behavior and update the URL when opening a modal. This has a few |
| 244 | +benefits: |
| 245 | + |
| 246 | +- It allows users to bookmark the modal and share the URL with others. |
| 247 | +- The modal becomes part of the browser history, so users can use the back and forward buttons. |
| 248 | +- It makes the modal content accessible to search engines (when using [SSR](/guide/server-side-rendering)). |
| 249 | +- It allows you to open the modal in a new tab. |
| 250 | + |
| 251 | +> [!NOTE] |
| 252 | +> To enable this feature, you need to use the [`inertia_rails-contrib`](https://github.com/skryukov/inertia_rails-contrib) gem, which provides base URL support for modals. |
| 253 | +
|
| 254 | +## Define a Base Route |
| 255 | + |
| 256 | +To define the base route for your modal, you need to use the `inertia_modal` renderer in your controller instead of the |
| 257 | +`inertia` one. It accepts the same arguments as the `inertia` renderer: |
| 258 | + |
| 259 | +```ruby |
| 260 | + |
| 261 | +class UsersController < ApplicationController |
| 262 | + def edit |
| 263 | + render inertia: 'Users/Edit', props: { # [!code --] |
| 264 | + render inertia_modal: 'Users/Edit', props: { # [!code ++] |
| 265 | + user:, |
| 266 | + roles: -> { Role.all }, |
| 267 | + } |
| 268 | + end |
| 269 | +end |
| 270 | +``` |
| 271 | + |
| 272 | +Then, you can pass the `base_url` parameter to the `inertia_modal` renderer to define the base route for your modal: |
| 273 | + |
| 274 | +```ruby |
| 275 | + |
| 276 | +class UsersController < ApplicationController |
| 277 | + def edit |
| 278 | + render inertia_modal: 'Users/Edit', props: { |
| 279 | + user:, |
| 280 | + roles: -> { Role.all }, |
| 281 | + } # [!code --] |
| 282 | + }, base_url : users_path # [!code ++] |
| 283 | + end |
| 284 | +end |
| 285 | +``` |
| 286 | + |
| 287 | +> [!WARNING] Reusing the Modal URL with different Base Routes |
| 288 | +> The `base_url` parameter acts merely as a fallback when the modal is directly opened using a URL. If you open the |
| 289 | +> modal from a different route, the URL will be generated based on the current route. |
| 290 | +
|
| 291 | +## Open a Modal with a Base Route |
| 292 | + |
| 293 | +Finally, the frontend needs to know that we're using the browser history to navigate between modals. To do this, you need |
| 294 | +to add the `navigate` attribute to the `ModalLink` component: |
| 295 | + |
| 296 | +:::tabs key:frameworks |
| 297 | +== Vue |
| 298 | + |
| 299 | +```vue |
| 300 | +<template> |
| 301 | + <ModalLink navigate href="/users/create"> Create User </ModalLink> |
| 302 | +</template> |
| 303 | +``` |
| 304 | + |
| 305 | +== React |
| 306 | + |
| 307 | +```jsx |
| 308 | +export default function UserIndex() { |
| 309 | + return ( |
| 310 | + <ModalLink navigate href="/users/create"> |
| 311 | + Create User |
| 312 | + </ModalLink> |
| 313 | + ) |
| 314 | +} |
| 315 | +``` |
| 316 | + |
| 317 | +::: |
| 318 | + |
| 319 | +Now, when you click the "Create User" link, it will open the modal and update the URL to `/users/create`. |
| 320 | + |
| 321 | +## Further Reading |
| 322 | + |
| 323 | +For advanced usage, configuration options, and additional features, check out [the official Inertia Modal documentation](https://inertiaui.com/inertia-modal/docs). |
0 commit comments