TurboMount
is a simple library that allows you to add highly interactive components from React, Vue, Svelte, and other frameworks to your Hotwire application.
To install Turbo Mount, add the following line to your Gemfile
and run bundle install
:
gem "turbo-mount"
Run the following command to install the necessary files:
bin/rails generate turbo_mount:install
This will add turbo-mount
package and framework dependencies to your package.json
or importmap.rb
, and create the Turbo Mount initialization file.
You can also install the necessary JavaScript files manually.
If your project utilizes build tools such as Vite, also install the turbo-mount
package:
npm install turbo-mount
# or with yarn
yarn add turbo-mount
# and the desired framework
npm install react react-dom
# or
npm install vue
# or
npm install svelte
If you're using Vite, don't forget to add framework-specific plugins to your vite.config.js
.
To use TurboMount
with importmaps, you need to pin the necessary JavaScript files in your config/importmap.rb
:
pin "turbo-mount", to: "turbo-mount.min.js"
pin "turbo-mount/react", to: "turbo-mount/react.min.js"
This ensures that turbo-mount
and its plugins are available in your application.
Also pin the desired framework:
bin/importmap pin react react-dom react-dom/client
# or
bin/importmap pin vue
# or
bin/importmap pin svelte
Note: Importmap-only mode is quite limited in terms of JavaScript dependencies. If you're using a more complex setup, consider using a bundler like Vite.
To begin using TurboMount
, start by initializing the library and registering the components you intend to use. Here's how to set it up with a React plugin:
import { TurboMount } from "turbo-mount";
import { registerComponent } from "turbo-mount/react";
import { HexColorPicker } from 'react-colorful';
const turboMount = new TurboMount(); // or new TurboMount({ application })
registerComponent(turboMount, "HexColorPicker", HexColorPicker);
If you prefer not to specify the application
explicitly, TurboMount
can automatically detect or initialize it. Turbo Mount uses the window.Stimulus
if available; otherwise, it initializes a new Stimulus application.
Use the following helpers to mount components in your views:
<%= turbo_mount("HexColorPicker", props: {color: "#034"}, class: "mb-5") %>
This will generate the following HTML:
<div data-controller="turbo-mount"
data-turbo-mount-component-value="HexColorPicker"
data-turbo-mount-props-value="{"color":"#034"}"
class="mb-5">
</div>
TurboMount
supports the following frameworks:
- React:
"turbo-mount/react"
- Vue:
"turbo-mount/vue"
- Svelte:
"turbo-mount/svelte"
To add support for other frameworks, create a custom plugin. See included plugins for examples.
To customize component behavior or pass functions as props, create a custom controller:
import { TurboMountController } from "turbo-mount";
export default class extends TurboMountController {
get componentProps() {
return {
...this.propsValue,
onChange: this.onChange,
};
}
onChange = (color) => {
// same as this.propsValue = { ...this.propsValue, color };
// but skips the rerendering of the component:
this.componentProps = { ...this.propsValue, color };
};
}
Then pass this controller to the registerComponent
method:
import HexColorPickerController from "controllers/turbo_mount/hex_color_picker_controller";
registerComponent(turboMount, "HexColorPicker", HexColorPicker, HexColorPickerController);
TurboMount
includes a registerComponents
function that automates the loading of components (requires the stimulus-vite-helpers
package). It also accepts an optional controllers
property to autoload customized controllers:
import { TurboMount } from "turbo-mount/react";
import { registerComponents } from "turbo-mount/registerComponents/react";
const controllers = import.meta.glob("./**/*_controller.js", { eager: true });
const components = import.meta.glob("/components/**/*.jsx", { eager: true });
const turboMount = new TurboMount();
registerComponents({ turboMount, components, controllers });
The registerComponents
helper searches for controllers in the following paths:
controllers/turbo-mount/${controllerName}
controllers/turbo-mount-${controllerName}
To specify a non-root mount target, use the data-<%= controller_name %>-target="mount"
attribute:
<%= turbo_mount("HexColorPicker", props: {color: "#430"}) do |controller_name| %>
<h3>Color picker</h3>
<div data-<%= controller_name %>-target="mount"></div>
<% end %>
The gem is available as open source under the terms of the MIT License.