Vue Features Compatibility
This page gives a feature-by-feature overview of core Vue features on Lynx. For the mental model behind Vue Lynx's dual-thread architecture, read Understanding the Dual-Thread Model.
Because Vue Lynx is built on the official Vue 3 runtime core, it aims to support the full Vue 3 API surface out of the box. The core rendering path — Composition API, SFCs, reactivity, template directives — works the same way you'd expect from standard Vue.
That said, Vue's API surface is large and we haven't had time to fully verify every corner of it. Below are critical Vue features that we've confirmed work effortlessly on Lynx — most require zero adaptation from a standard Vue codebase. Where Lynx-specific caveats exist, they are called out inline.
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, and <style module> all work on Lynx. <style scoped> and v-bind() in CSS are not yet supported — vote on #78 and #79 if you need them.
Feature support details
For dynamic styling, use computed :style bindings as a workaround for v-bind():
Component v-model
Vue's v-model on components creates a two-way binding between parent and child. The child uses defineModel() (Vue 3.4+) to declare a model prop, and the parent binds it with v-model.
The example demonstrates:
- Default model —
defineModel<number>()withv-model="count"for a counter - Named models —
defineModel('title')+defineModel('body')withv-model:title/v-model:body - Manual input binding — the workaround for native
<input>(see caveat below)
v-model on native <input> elements is not yet supported. Lynx inputs use synchronous Main Thread APIs (getValue() / setValue()) that are inaccessible from the background thread where Vue runs. Use :value + @input manually 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:
- Default slot — content projected into a
<Card>component - Named slots —
#headerand#footerwith fallback content - 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.
<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:
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: