---
title: "LoadingOverlay"
description: "A loading mask over a container or the whole screen."
category: Feedback
status: beta
since: 0.3.4
tags: [loading, overlay, mask]
syncStatus: reviewed
verified: true
---

<script setup lang="ts">
import { ref } from 'vue'
const loading = ref(false)
</script>

## Usage

### In a Container
The mask covers the default slot, and the content underneath stays visible.
:::TuffDemoWrapper{demo="LoadingOverlayLoadingOverlayContainerDemo" code-lang="vue"}
---
code: |
  <template>
    <TxButton @click="loading = !loading">Toggle</TxButton>
    <TxLoadingOverlay :loading="loading" text="Loading...">
      <div class="content">Content</div>
    </TxLoadingOverlay>
  </template>
---
:::

### Fullscreen
`fullscreen` teleports the mask to `body` to cover the viewport and skips the default slot.
:::TuffDemoWrapper{demo="LoadingOverlayLoadingOverlayFullscreenDemo" code-lang="vue"}
---
code: |
  <template>
    <TxButton @click="loading = !loading">Toggle</TxButton>
    <TxLoadingOverlay fullscreen :loading="loading" text="Loading..." />
  </template>
---
:::

### Background Task
A local overlay combined with Toast, Tooltip, and Spinner; the task queue stays visible while it refreshes, so the layout doesn't jump.
:::TuffDemoWrapper{demo="ComponentsFeedbackTaskCenterDemo" code-lang="vue"}
---
code: |
  <template>
    <TxLoadingOverlay :loading="syncing" text="Refreshing task queue…" :spinner-size="22">
      <TxProgressBar :percentage="72" status="warning" />
      <TxProgressBar :percentage="96" status="success" />
    </TxLoadingOverlay>
  </template>
---
:::

### Best Practices

- Use a local overlay for short waits over existing content — refresh, save, recalculate — so the old content stays visible.
- Reserve `fullscreen` for flows that must block the whole app, such as startup, workspace switching, or destructive work that can't run in parallel.
- Name the action in the text: "Refreshing task queue…" beats a generic "Loading…".
- Before first content exists, use `TxLoadingState` or a skeleton, not an overlay.

## API Reference

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `loading` | `boolean` | `false` | Shows the overlay. |
| `fullscreen` | `boolean` | `false` | Teleports to `body` and covers the viewport. |
| `text` | `string` | `''` | Text below the spinner; without it, only the spinner shows. |
| `spinnerSize` | `number` | `18` | Spinner size in px. |
| `background` | `string` | `'color-mix(in srgb, var(--tx-bg-color, #fff) 70%, transparent)'` | Mask background, written to `--tx-loading-overlay-bg`. |

### Slots

| Slot | Props | Description |
|------|------|-------------|
| `default` | - | Content the local overlay covers; not rendered in fullscreen mode. |

## Overview

- Local mode wraps the default slot in a `position: relative` container and renders the absolute mask only while `loading`.
- Fullscreen mode takes a fresh shared z-index each time it opens.
- The mask has `role="status"` and `aria-live="polite"`, so screen readers announce `text`; no extra announcement is needed.
- Fullscreen mode parks focus on the mask and traps Tab, then returns focus to the previous element on close.
- The mask has no modal semantics (no `aria-modal`); use `TxModal` or a Dialog component when you need a modal.

## Technologies

- The mask adds blur and saturation through `backdrop-filter`.
- Source: `packages/tuffex/packages/components/src/loading-overlay/`.

<TuffDocSourceLink />
