Vue Features Compatibility

Vue Lynx is built on the official Vue 3 runtime core (@vue/runtime-core), so you should expect your Vue code to just work. The core rendering path — Composition API, SFCs, reactivity, template directives — works the same way you'd expect from standard Vue, with no Lynx-specific adaptation required.

Below is a feature-by-feature breakdown of the Vue features we've verified on Lynx. Where Lynx-specific caveats exist, they are called out inline. For details on how the dual-thread architecture works under the hood, see Understanding the Dual-Thread Model.

Reactivity + Composables

Vue Lynx reuses 100% of Vue's reactivity core (@vue/reactivity). Every reactivity API works identically to standard Vue, with no Lynx-specific caveats or adaptations.

The example below demonstrates reactive() + toRefs(), and a useStopwatch() composable that encapsulates reactive state:

SFC CSS Features

Plain <style> blocks, imported .css files, <style module>, and v-bind() in CSS all work on Lynx. <style scoped> is not yet supported — vote on #78 if you need it.

Feature support details
FeatureStatus
<style> (plain)Works
Imported .css filesWorks
<style module>Works
v-bind() in <style>Works (requires config, see below)
<style scoped>Upcoming (#78)

v-bind() in <style> requires one config option so the Lynx engine recognizes CSS custom properties in inline styles:

lynx.config.ts
pluginVueLynx({
  enableCSSInlineVariables: true,
})

v-model

Vue's v-model creates two-way bindings. On components, the child uses defineModel() (Vue 3.4+) to declare a model prop, and the parent binds it with v-model. On native <input> and <textarea> elements, v-model works just like standard Vue, including the .lazy, .trim, and .number modifiers.

The example demonstrates:

  1. Default modeldefineModel<number>() with v-model="count" for a counter
  2. Named modelsdefineModel('title') + defineModel('body') with v-model:title / v-model:body
  3. Native input v-modelv-model directly on <input>
Caveat

v-model on <select>, <input type="checkbox">, and <input type="radio"> is not supported — Lynx has no native equivalents for these elements. Use component-level v-model with custom components instead.

Slots

Vue slots are the primary composition mechanism for passing template content into child components. Vue Lynx supports default slots, named slots, and scoped slots.

The example below demonstrates all three patterns:

  1. Default slot — content projected into a <Card> component
  2. Named slots#header and #footer with fallback content
  3. Scoped slot — a <DataList> exposes each item to the parent for custom rendering

Provide / Inject

Vue's provide and inject APIs let an ancestor component serve as a dependency injector for all its descendants, regardless of how deep the component hierarchy is. This avoids prop drilling through intermediate components.

The example below provides a reactive theme ref and a static appName string at the root. A grandchild component injects both — the middle layer passes nothing down.

Suspense

Vue's <Suspense> displays fallback content while waiting for async components to resolve. On Lynx, <Suspense> works with both async setup() (top-level await in <script setup>) and defineAsyncComponent for lazy-loading.

Transition

Vue's <Transition> and <TransitionGroup> components apply enter/leave animations when elements are inserted or removed.

Warning

<Transition> and <TransitionGroup> are experimental. Always pass an explicit :duration prop — getComputedStyle() is unavailable from the background thread. Move (FLIP) animations in <TransitionGroup> are not supported since getBoundingClientRect() is unavailable.

Options API

Vue 3 ships the Options API alongside the Composition API for backward compatibility. By default, Vue Lynx enables it (optionsApi: true in the plugin), but you can disable it to reduce bundle size:

lynx.config.ts
pluginVueLynx({
  optionsApi: false, // tree-shakes the Options API runtime (~9 kB)
})

The example below uses defineComponent with data(), computed, watch, methods, and the mounted lifecycle hook:

Unsupported Features

Some Vue built-in features are not yet adapted to the dual-thread native environment:

FeatureReasonAlternative
<KeepAlive>Requires an internal storage container (createElement('div')) with no native equivalentManual state caching
<Teleport>Requires querySelector to resolve string targets, unavailable in the dual-thread architectureConditional rendering at the target location
<Transition> auto-durationgetComputedStyle() is unavailable on the background threadAlways pass an explicit :duration prop