Skip to content

Configuration ​

LayerGlobalConfig ​

Global configuration passed via app.use(VueLiteLayer, globalConfig), serving as defaults for all layers.

PropertyTypeDefaultDescription
footerboolean | string | ComponenttrueFooter area: true shows default buttons, false hides, pass a string or component for custom footer
shadebooleantrueWhether to show the shade overlay
shadeClosebooleantrueWhether clicking the shade closes the layer
maxWidthstring'none'Maximum width (CSS value, e.g. '800px', '90%')
maxHeightstring'none'Maximum height (CSS value)
sizeWindowSize{ width: '300px', height: '400px' }Default layer size
locationPositionPreset | Position'CC'Layer position, see below
teleportstring | HTMLElement | RendererNode'body'Teleport target, CSS selector or DOM element
maxbooleantrueWhether to allow maximize
minbooleanfalseWhether to allow minimization to the Teleport target's bottom dock
closebooleantrueWhether to show the close button
closeOnOkbooleanfalseWhether OK in the default footer closes automatically; keep false for async forms
closeOnEscbooleantrueWhether Esc requests closing the layer
trapFocusbooleantrueWhether Tab focus is kept inside the layer
restoreFocusbooleantrueWhether to restore focus after the top layer closes
i18n{ locale?: string; messages?: object }{ locale: 'zh-CN' }Internationalization configuration
asyncContentAsyncContentConfig—Loading, failure and retry presentation for async content
bannerbooleantrueWhether to print the version banner during plugin installation

LayerConfig ​

Per-layer configuration passed via openLayer(config, appContext). Inherits all LayerGlobalConfig properties and adds the following layer-specific ones:

PropertyTypeDefaultDescription
idstringAuto-generatedUnique layer identifier, usually no need to set manually
uniqueGroupstring—Unique group identifier; only one layer per group can be open
titlestring''Layer title
contentComponent | HTMLElement | string—Layer content: Vue component, HTMLElement, or trusted HTML string. String content is rendered as HTML, so do not pass unsanitized user input. HTMLElement content is moved into the layer and restored to its original DOM position on content switch or unmount when possible
textContentstring—Safe plain text content. Takes precedence over content
contentType'html' | 'text''html'Render mode for string content; defaults to legacy HTML behavior
propsobject | nullnullProps to pass to the content component
onOkLayerCallback | nullnullConfirm callback, receives data from the content component
onCancelLayerCallback | nullnullCancel callback
onCommandLayerCallback | nullnullCustom command callback
beforeClose(context) => boolean | Promise<boolean>nullClose guard; return false to keep the layer open
onOpen() => voidnullCalled when the layer mounts
onOpened() => voidnullCalled after the enter animation completes
onClose(context) => voidnullCalled when the close guard passes and the leave animation begins
onClosed(context) => voidnullCalled after the leave animation completes, before unmount

HTML content security

String content is for trusted HTML, and runtime rendering does not sanitize HTML for you. Prefer textContent or contentType: 'text' for plain text or user input. If you must render rich user content, sanitize it with a trusted sanitizer first.

Close Control and Accessibility ​

All close paths (header, shade, Esc, footer and instance close()) pass through beforeClose, including synchronous and asynchronous guards:

ts
openLayer({
  beforeClose: async ({ reason }) =>
    reason === 'shade' ? window.confirm('Discard unsaved changes?') : true
}, appContext)

While beforeClose is awaiting, additional close requests on the same Layer are coalesced into the most recent intent and processed serially through the guard — concurrent requests cannot race ahead. The first guard that returns false keeps the Layer open; the first that returns a truthy value starts the leave animation.

Layers focus themselves on open, trap Tab by default, and restore focus when the active top layer closes. A shaded layer teleported to body locks page scroll; nested layers use reference counting and restore page styles after the final close. SSR or hosts that lack document.body do not throw. The focus trap skips elements hidden by CSS or ARIA (display: none, visibility: hidden, aria-hidden="true", hidden ancestors, etc.) so the Tab order never lands on an unreachable control.

With min: true, the header shows a minimize button. A minimized window appears in a dock at the bottom of its Teleport target and no longer retains its shade, scroll lock, or focus trap. Clicking its dock item restores and brings it to the front, preserving its previous normal or maximized state.

Async Content ​

defineAsyncComponent() content shows a loading state and a retry UI on failure:

ts
openLayer({
  content: AsyncEditor,
  asyncContent: {
    loadingText: 'Loading editor…',
    errorText: 'Editor failed to load',
    retryText: 'Retry',
    timeout: 10_000,
    maxRetries: 3,
    retryDelay: 500,
    onError: reportError
  }
}, appContext)

timeout is the loading timeout in milliseconds; omit it to disable timeout. maxRetries limits manual retries and retryDelay delays a retry. Use onTimeout and onRetry(retryCount) for observability. Closing a Layer clears library-owned timeout/retry timers; aborting the async loader itself remains the responsibility of the request layer, for example with AbortController.

Error callback dedup and propagation

onError fires at most once for the same error across the timeout and synchronous child-render paths — duplicates are deduped so a single error never produces two alerts. Render errors are not swallowed: they continue to propagate to ancestor errorCaptured hooks and the app-level errorHandler for unified observability. The library's onError only mirrors the error into the retry UI.

The footer property controls the layer's bottom button area, supporting three modes:

Shows the built-in "OK" and "Cancel" buttons. Clicking a button triggers internal ok / cancel events, which the content component can listen for via useLayerEvent's onOk / onCancel.

The default footer only emits ok / cancel; it does not close the Layer directly. Content or a custom footer must call close() explicitly. Use closeOnOk: true only for simple confirmations.

typescript
openLayer({
  title: 'Default Buttons',
  content: MyComponent,
  footer: true, // Default
}, appContext)

Does not render the footer area. Suitable when the content component has its own action buttons, or when showing information only.

typescript
openLayer({
  title: 'No Footer',
  content: MyComponent,
  footer: false,
}, appContext)

Pass a Vue component to fully replace the default button area. Custom footer components use the footer-specific API (emitOk / emitCancel / emitCommand) to interact with the layer:

vue
<!-- CustomFooter.vue -->
<script setup>
import { useLayerEvent } from 'vue-lite-layer'

// Footer-specific API
const { emitOk, emitCancel, emitCommand, close } = useLayerEvent()

const handleSave = () => {
  emitOk()              // Notify Container: confirm
  close()
}
const handleCancel = () => {
  emitCancel()           // Notify Container: cancel
  close()
}
</script>

<template>
  <div style="display: flex; justify-content: flex-end; padding: 10px; gap: 8px; border-top: 1px solid #f0f0f0;">
    <button @click="handleCancel">Cancel</button>
    <button @click="handleSave">Save</button>
  </div>
</template>

Using the custom footer component:

typescript
import CustomFooter from './CustomFooter.vue'

openLayer({
  title: 'Custom Footer',
  content: MyComponent,
  footer: CustomFooter,
}, appContext)

Shade / ShadeClose Details ​

shade and shadeClose work together to control the overlay behavior:

shadeshadeCloseEffect
truetrueShow shade, clicking shade closes the layer (default)
truefalseShow shade, clicking shade does NOT close (for critical operations)
false—No shade, page remains interactive
typescript
// With shade, click to close (default)
openLayer({ shade: true, shadeClose: true, ... }, appContext)

// With shade, click does NOT close
openLayer({ shade: true, shadeClose: false, ... }, appContext)

// No shade
openLayer({ shade: false, ... }, appContext)

TIP

When shade: false, the layer does not block page interaction. You can open multiple shade-free layers that stack on top of each other.

WindowSize ​

Layer size type, accepts CSS string values:

typescript
interface WindowSize {
  width?: string   // e.g. '500px', '80%'
  height?: string  // e.g. '400px', '60%'
}

PositionPreset ​

Position preset enum values, in ColumnRow format:

ValueDescription
'LT'Top Left
'LC'Left Center
'LB'Bottom Left
'CT'Top Center
'CC'Center (default)
'CB'Bottom Center
'RT'Top Right
'RC'Right Center
'RB'Bottom Right

You can also pass a custom coordinate object:

typescript
interface Position {
  top: string   // CSS top value, e.g. '100px'
  left: string  // CSS left value, e.g. '200px'
}

LayerCallback ​

Layer callback function type:

typescript
type LayerCallback = (commandOrMessage?: unknown, message?: unknown) => void

Configuration Priority ​

Configuration merge priority (from highest to lowest):

  1. Configuration passed in the openLayer() call
  2. Global configuration passed in app.use(VueLiteLayer, globalConfig)
  3. Built-in defaults (defaultConfig)
typescript
// Built-in defaults
{
  teleport: 'body',
  size: { width: '300px', height: '400px' },
  footer: true,
  shade: true,
  shadeClose: true,
  maxWidth: 'none',
  maxHeight: 'none',
  location: 'CC',
  max: true,
  close: true,
  closeOnOk: false,
  closeOnEsc: true,
  trapFocus: true,
  restoreFocus: true,
  i18n: { locale: 'zh-CN' },
  banner: true
}

Released under the Apache-2.0 License.