Skip to content

App Switcher

The AppSwitcher component provides a Google-style application switcher. It renders a trigger button that opens a popover containing a grid of application shortcuts. Each tile intelligently resolves its visual representation using an icon, an image, or an initials fallback, and fully supports both internal SPA navigation and external absolute URLs.

Features

  • Intelligent Tile Resolution: Supports vector icon (Nuxt Icon), raster image (URL or public path), or an automatic initials fallback for each app.
  • Configurable Grid: Customize the number of columns in the popover via the columns prop.
  • SPA & External Navigation: Uses a standard to property, allowing internal paths to trigger SPA navigation and absolute URLs to perform a full application switch.
  • Popover Footer: Optional footer link (similar to Google's "More from..." row).
  • Seamless Navigation Bar Integration: Easily added to the NavigationBar via the otherApps prop or the rightPreItems slot.

Props

PropTypeRequiredDefaultDescription
appsAppSwitcherApp[]YesArray of application entries to display in the grid.
triggerIconstringNo"i-lucide-grip"Nuxt Icon name for the trigger button.
triggerLabelstringNo"Apps"Accessible label (aria-label) for the trigger button.
columnsnumberNo3Number of columns in the app switcher grid.
footerTostringNoOptional link URL shown in the popover footer.
footerLabelstringNo"More"Label for the optional popover footer link.

AppSwitcherApp Interface

Each entry in the apps array conforms to the exported AppSwitcherApp interface:

typescript
export interface AppSwitcherApp {
  /** Name of the application, displayed below the tile. */
  name: string;
  /** Router path (internal SPA nav) or absolute URL (full app switch). */
  to: string;
  /** Nuxt Icon name, e.g. "i-lucide-mail". Takes precedence over `image`. */
  icon?: string;
  /** URL or public/ path to a raster image. Used only when `icon` is unset. */
  image?: string;
  /** Optional alt text for the image; defaults to `name`. */
  alt?: string;
}

Slots

SlotDescription
topOptional content rendered above the apps grid.
bottomOptional content rendered below the apps grid. Overrides the default footer link generated by the props.

Usage

Basic Implementation

To use the AppSwitcher, define an array of AppSwitcherApp objects and pass it to the apps prop.

vue
<script setup lang="ts">
import type { AppSwitcherApp } from "@dcc-bs/common-ui.bs.js/components";

const apps: AppSwitcherApp[] = [
  { name: "Mail", to: "https://mail.google.com", icon: "i-lucide-mail" },
  { name: "Calendar", to: "https://calendar.google.com", icon: "i-lucide-calendar" },
  {
    name: "Maps",
    to: "https://maps.google.com",
    image: "https://www.google.com/images/branding/product/1x/maps_64dp.png",
  },
  { name: "Drive", to: "https://drive.google.com" } // Falls back to 'D' initial
];
</script>

<template>
  <AppSwitcher :apps="apps" />
</template>

You can add a link to the bottom of the popover using the footerTo and footerLabel props.

vue
<template>
  <AppSwitcher
    :apps="apps"
    footer-to="https://about.google/products/"
    footer-label="More"
  />
</template>

Customizing the Grid and Trigger

Adjust the grid layout by changing the number of columns, and swap out the trigger icon using triggerIcon.

vue
<template>
  <AppSwitcher
    :apps="apps"
    trigger-icon="i-lucide-layout-grid"
    :columns="2"
  />
</template>

Tile Resolution Logic

When rendering an application tile, the component determines its visual representation using the following priority (first match wins):

  1. Icon (icon): If provided, renders a vector Nuxt Icon. This is SSR-safe and requires no external image assets, making it the preferred choice for logos.
  2. Image (image): If icon is omitted but image is provided, renders a standard <img> tag. This accepts external URLs or local paths from your public/ directory.
  3. Initials Fallback: If neither icon nor image is provided, the component generates a tinted tile using the first letter of the application's name.

Integration with NavigationBar

The AppSwitcher is commonly placed inside the NavigationBar. You can either insert it manually via the rightPreItems slot, or use the otherApps prop directly on the NavigationBar for seamless integration.

Using the otherApps prop

vue
<script setup lang="ts">
import type { AppSwitcherApp } from "@dcc-bs/common-ui.bs.js/components";

const apps: AppSwitcherApp[] = [
  { name: "Mail", to: "https://mail.google.com", icon: "i-lucide-mail" },
  { name: "Docs", to: "https://docs.google.com", icon: "i-lucide-file-text" }
];
</script>

<template>
  <NavigationBar :other-apps="apps" />
</template>

Using the rightPreItems Slot

vue
<template>
  <NavigationBar>
    <template #rightPreItems>
      <AppSwitcher :apps="apps" />
    </template>
  </NavigationBar>
</template>

Developed with ❤️ by the DCC. Documentation released under the MIT License.