App
npx @vyui/cli add appOverview
VyApp is the recommended root wrapper for a Vy UI app. It owns the dark-mode class-toggle + remount contract that useColorMode requires of an app root, mounts the shared overlay host so teleporting surfaces work with zero setup, and reports the root's size whenever it changes.
<script setup lang="ts">
import { VyApp } from '@vyui/kit'
</script>
<template>
<VyApp>
<!-- your screens -->
</VyApp>
</template>
import { createApp } from '@lynx-js/vue'
import { VyUI } from '@vyui/kit'
import App from './App.vue'
createApp(App).use(VyUI).mount('#app')
VyApp once, at the top of the tree. Everything it wires up — the dark ramp, the overlay host, the viewport signal — applies to the whole app below it.Usage
Dark mode
VyApp reads useColorMode's mode / isDark and applies both pieces of the app-root contract: the .dark class and a :key="mode" remount. Lynx native only applies a class change to freshly mounted nodes, so toggling .dark on an already-mounted tree would not re-skin it — keying on mode remounts the subtree on every change, turning that platform quirk into the mechanism. You get this for free just by wrapping your app; nothing further to wire up.
Overlay host
By default VyApp mounts OverlayRoot (from @vyui/core) as its first child, so Modal, Tray, Toast, and other teleporting components work without any hand-wiring. Set overlays to false and place your own <OverlayRoot /> if you need control over where it sits in the tree.
<template>
<VyApp :overlays="false">
<OverlayRoot />
<!-- your screens -->
</VyApp>
</template>
Radius token
Pass radius to set --ui-radius (in rem) on the root, overriding the default shipped in @vyui/kit/style.css.
<VyApp :radius="0.75">
<!-- your screens -->
</VyApp>
Viewport size
VyApp emits viewport-change with { width, height } on mount and on every resize (rotation, split-screen), sourced from the background-thread layoutchange event. main-thread-* attrs do not reliably attach to this root, so this is the supported way to observe root size.
<VyApp @viewport-change="(size) => console.log(size.width, size.height)">
<!-- your screens -->
</VyApp>
Reading color mode from the slot
The default slot receives { mode, isDark } — the same values useColorMode() returns — so a descendant can react to color mode without importing the composable itself.
<VyApp v-slot="{ mode, isDark }">
<text>Current mode: {{ mode }} ({{ isDark ? 'dark' : 'light' }})</text>
</VyApp>
Features and behavior
- Applies the
.darkclass and a:key="mode"remount together, so color mode toggles correctly on Lynx native and on web. - Mounts
OverlayRootas the first child by default; opt out withoverlays="false"to place it yourself. radiussets--ui-radiusinline, in rem.- Emits
viewport-changeon mount and resize, from the background-threadlayoutchangeevent. - The default slot exposes
{ mode, isDark }for consumers that want color mode without callinguseColorMode()directly.
Props
| Prop | Default | Type |
|---|---|---|
overlays | true | boolean | undefinedMount the overlay host (`OverlayRoot`) as the first child of the root so teleported surfaces (Modal, Tray, Toast, …) work without hand-wiring. Opt out when placing `<OverlayRoot />` yourself. |
radius | — | number | undefinedCorner radius in rem — sets `--ui-radius` on the root. Omit to keep the `@vyui/kit/style.css` default. |
ui | — | Partial<Record<"root", any>> | undefined |
Emits
| Event | Payload |
|---|---|
viewport-change | [size: { width: number; height: number; }] |
Slots
| Slot | Bindings |
|---|---|
default | { mode: ColorMode; isDark: boolean; } |
Styling and theming
Override globally through appConfig.ui.app or locally with the ui prop.
| UI slot | Purpose |
|---|---|
root | The app-root element. Paints the bg-default surface token and fills the viewport (w-full h-full). |
Platform notes
- The dark-mode remount relies on Lynx native applying class changes only to freshly mounted nodes —
:key="mode"turns that into the toggle mechanism. SeeuseColorModefor the full rationale. viewport-changeis sourced from the background-threadlayoutchangeevent rather than amain-thread-*binding, because those attrs do not reliably fall through onto this root.- Components that teleport (
Modal,Tray,Toast, …) need anOverlayRootsomewhere in the tree to render at all —VyAppprovides one by default so this is rarely something you need to think about.
Related components
Trayfor a bottom sheet mounted through the overlay hostVyAppprovides.Modalfor a centered blocking dialog, same overlay host.- Theming → Dark Mode and Theming → Overrides for runtime theme overrides.