@kadal/deck-vue

The Vue renderer for Kadal Deck (@kadal/deck): Vue components as islands on a slide.
583
Install
npm install @kadal/deck-vue
Latest Version:0.4.5
Vue:3
License:AGPL-3.0-or-later
Last Updated:Oct 23, 2026
Links: GitHub  ·  npm
Maintainer: pmithunish

@kadal/deck-vue

The Vue renderer for Kadal Deck, presentations written in MDX: Vue code as an island on a slide, loaded only when its slide appears.

Vue islands guide · Islands in any framework · Docs · Source

npm install @kadal/deck-vue vue

Vue 3 components on a deck slide.

// once, where the deck is created
import { registerLazyRenderer } from "@kadal/deck";

registerLazyRenderer("vue", () => import("@kadal/deck-vue").then((m) => m.vueRenderer));
<Island
  framework="vue"
  load={() => import("./chart.ts").then((m) => m.Chart)}
  props={{ data }}
  client="slide"
/>

Registered by name and loaded on arrival, neither Vue's runtime nor the component is in the deck's first chunk — measured at 64 kB off the showcase deck's opening load, which matters once a deck can reach for ten frameworks and uses one.

A component written as options is recognised on its own. A functional Vue component is a plain function, indistinguishable from a React or Solid one, so it has to say so:

import { deckVue } from "@kadal/deck-vue";

export const Chart = deckVue((props) => h("div", props.label));

or framework="vue" on the island, which the example above already does.

What it does with props

createApp(Component, props) takes its props once; handing it new ones later does nothing. So the app is mounted around a reactive bag the render function reads, and new props mutate that bag in place. The island is re-rendered, not rebuilt — a chart keeps its animation, a half-typed form keeps what you typed. Without this the renderer would have to remount on every click of the slide.

What it does not do

No ssr. It would pull @vue/server-renderer into every deck with a Vue island, and the deck's print and export paths run a real browser, where islands hydrate like anywhere else. It goes in when a surface appears that genuinely cannot run JS.

No live cross-framework children. children arrive as HTML and go in as the default slot's markup. A React subtree cannot keep its state inside a Vue component, and pretending otherwise produces bugs nobody can explain. Interactivity inside an island belongs to that island.

No .vue files yet. A single-file component needs @vitejs/plugin-vue in the deck's Vite config; the renderer handles what that plugin produces (it looks for __vccOpts and __file), but wiring the plugin into the deck's own Vite plugin is still to do.

Licence

AGPL-3.0-or-later, with a commercial licence available — the same terms as the engine. See LICENSING.md.

Related Packages

@keynote/cli

CLI for creating Keynotes using Vue

613 240
vue-carousel-lite

Fast, Lightweight Vue Carousel With Touch, Mouse, Keyboard, Wheel & SSR support

5,144 0
vue-mark-display

a Vue Component to generate Markdown-based slides

5,892 309
iles

Vite & Vue powered static site generator with partial hydration

29,782
@islands/hydration

Hydration utilities for îles

18,451

Version History

Version Released Vue License
0.4.5 ^3.5.0 AGPL-3.0-or-later
0.4.4 ^3.5.0 AGPL-3.0-or-later
0.4.3 ^3.5.0 AGPL-3.0-or-later
0.4.2 ^3.5.0 AGPL-3.0-or-later
0.4.1 ^3.5.0 AGPL-3.0-or-later
Pre-releases (1)
Version Released License
0.0.0-stage