{"id":12613,"library":"vue-turbolinks","title":"Vue Turbolinks Hotwire Adapter","description":"vue-turbolinks is a JavaScript package designed to facilitate the integration of Vue.js components into applications that utilize Turbolinks or Hotwire's Turbo. Its primary function is to manage the lifecycle events of Vue components—specifically their proper setup and teardown—within the context of a Turbolinks/Turbo page navigation cycle. This allows developers to incrementally add interactive Vue elements to traditional server-rendered applications without converting them into full Single-Page Applications (SPAs). The current stable version is 2.2.2, with recent minor updates indicating active maintenance. A key differentiator is its explicit focus on solving the challenges of combining Vue's reactivity with Turbolinks'/Turbo's caching mechanisms, making it unsuitable and unnecessary for projects already employing client-side routing libraries like Vue Router.","status":"active","version":"2.2.2","language":"javascript","source_language":"en","source_url":"https://github.com/jeffreyguenther/vue-turbolinks","tags":["javascript","vue","turbolinks","hotwire","turbo"],"install":[{"cmd":"npm install vue-turbolinks","lang":"bash","label":"npm"},{"cmd":"yarn add vue-turbolinks","lang":"bash","label":"yarn"},{"cmd":"pnpm add vue-turbolinks","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for the mixin functionality, as vue-turbolinks is an adapter for Vue.js components.","package":"vue","optional":false}],"imports":[{"note":"This is the default export used for global installation via `Vue.use()`.","wrong":"const TurbolinksAdapter = require('vue-turbolinks');","symbol":"TurbolinksAdapter","correct":"import TurbolinksAdapter from 'vue-turbolinks';"},{"note":"This is a named export for integrating the mixin into individual Vue components via the `mixins` option.","wrong":"const { turbolinksAdapterMixin } = require('vue-turbolinks');","symbol":"turbolinksAdapterMixin","correct":"import { turbolinksAdapterMixin } from 'vue-turbolinks';"},{"note":"The global adapter can be configured with an options object, for example, to customize the teardown event.","symbol":"Options for Vue.use()","correct":"Vue.use(TurbolinksAdapter, { destroyEvent: 'turbo:before-cache' });"}],"quickstart":{"code":"import { turbolinksAdapterMixin } from 'vue-turbolinks';\nimport Vue from 'vue';\n\n// A mock App component for demonstration\nconst App = {\n  template: '<div>Hello from Vue and Turbolinks! Count: {{ count }} <button @click=\"count++\">Increment</button></div>',\n  data() {\n    return { count: 0 };\n  },\n  mounted() {\n    console.log('App mounted!');\n  },\n  beforeDestroy() {\n    console.log('App beforeDestroy!');\n  }\n};\n\ndocument.addEventListener('turbo:load', () => {\n  const element = document.getElementById(\"hello\");\n\n  if (element != null) {\n    new Vue({\n      el: element,\n      template: '<App/>',\n      mixins: [turbolinksAdapterMixin],\n      components: { App }\n    });\n    console.log('Vue app initialized on turbo:load.');\n  } else {\n    console.log('No #hello element found, skipping Vue initialization.');\n  }\n});\n\n// Simulate a Turbolinks/Turbo page load for demonstration\n// In a real app, this would be triggered by navigation.\nsetTimeout(() => {\n  const rootDiv = document.createElement('div');\n  rootDiv.id = 'hello';\n  document.body.appendChild(rootDiv);\n  document.dispatchEvent(new Event('turbo:load'));\n}, 500);\n\nsetTimeout(() => {\n  const elementToRemove = document.getElementById('hello');\n  if (elementToRemove) {\n    elementToRemove.parentNode.removeChild(elementToRemove);\n  }\n  document.dispatchEvent(new Event('turbo:before-cache')); // Simulate cache event\n}, 3000);","lang":"javascript","description":"This quickstart demonstrates how to initialize a Vue component using the `turbolinksAdapterMixin` on a `turbo:load` event, ensuring proper lifecycle management with Hotwire/Turbolinks. It includes a basic Vue component and simulates the DOM changes and events typical in a Turbo application."},"warnings":[{"fix":"If using a client-side router, remove `vue-turbolinks` as it provides no benefit and can introduce conflicts. If not using a client-side router, ensure Turbolinks/Turbo is correctly configured.","message":"Do not use `vue-turbolinks` if your application already employs a client-side JavaScript routing library like `vue-router`. This adapter is designed for traditional server-rendered applications enhanced by Turbolinks or Hotwire's Turbo, not for Single-Page Applications (SPAs).","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always wrap Vue `<transition>` components within a standard DOM element (e.g., `<div>`) at the root level of your component's template. For example, instead of `<template><transition>...</transition></template>`, use `<template><div><transition>...</transition></div></template>`.","message":"When a `$root` Vue component's direct root node is a `<transition>` element, its destruction upon `turbo:before-cache` or `turbolinks:before-cache` can fail with `NoModificationAllowedError`. This is because directly setting `outerHTML` on a Vue transition component's root might not be supported or stable.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Upgrade to `vue-turbolinks` version 2.2.1 or higher to ensure the `turbolinksAdapterMixin` named export functions as expected.","message":"Prior to v2.2.1, the `turbolinksAdapterMixin` might not have been correctly exported, causing issues when attempting to import it as a named export.","severity":"breaking","affected_versions":"<2.2.1"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Wrap your root `<transition>` component in a regular HTML element (e.g., `<div>`) in your Vue component's template.","cause":"Attempting to destroy a Vue root component whose top-level element is a `<transition>` component during a Turbolinks/Turbo cache event.","error":"NoModificationAllowedError: Failed to set the 'outerHTML' property on 'Element'"},{"fix":"Ensure `import Vue from 'vue';` is present at the top of your file or that Vue is globally exposed before attempting to install the adapter globally. If using Webpack, check your configuration for Vue aliasing.","cause":"Attempting to use `Vue.use(TurbolinksAdapter)` before Vue is properly imported or globally available.","error":"TypeError: Cannot read properties of undefined (reading 'use') when installing globally"}],"ecosystem":"npm"}