Client Plugin Prerequisites
This guide covers the Vue plugins, directives, and VUEDA-specific setup functions that must be registered before mounting a VUEDA client application. It explains what each dependency provides, which built-in components rely on it, and what fails when it is missing. The setup imports the built-in theme to register component styling classes and calls setupDefaultListCrud and setupDefaultObjectCrud to activate the shared CRUDL data path used by built-in views.
The guide assumes familiarity with Vue 3 application setup (createApp, app.use). For the tutorial-style walkthrough that shows the full main.js in context, see Start Building. For theme customization beyond the base tokens, see Customize VUEDA Appearance.
Goal and Preconditions
The objective is a main.js that registers all required plugins and setup functions so that VUEDA's built-in views, components, and stores function correctly.
Before you begin:
The project must install @arrai-innovations/vue-sonner, our maintained fork of vue-sonner. It is a peer dependency of @arrai-innovations/vueda and backs the toast surface. VUEDA's control and widget components are first-party (built on Reka UI, which VUEDA bundles), so there is no third-party component-library peer dependency to install. Pinia and Vue Router must also be installed; they are assumed throughout but are not VUEDA-specific.
If you are using the built-in vueda-tailwind theme (recommended), you also need tailwindcss and @tailwindcss/vite installed as dev dependencies, and the Vite plugin registered in vite.config.js. Tailwindcss is a build tool, not a runtime peer dependency of VUEDA.
Registration Order
Plugin registration follows a specific order. Some steps have dependencies on earlier steps; others are order-independent but grouped by concern for clarity.
import TheApp from "./TheApp.vue";
import { getRouter } from "./router/index.js";
import "@vueda/theme/vueda-tailwind/index.js";
import { setupDefaultListCrud } from "@vueda/utils/listCrud.js";
import { setupDefaultObjectCrud } from "@vueda/utils/objectCrud.js";
import { createPinia } from "pinia";
import { createApp } from "vue";
// 1. CRUDL adapters (the theme import above registers defaults before app creation)
setupDefaultListCrud();
setupDefaultObjectCrud();
// 2. App and core plugins
const app = createApp(TheApp);
const pinia = createPinia();
const router = getRouter(app, pinia);
app.use(pinia);
app.use(router);
// 3. Mount
app.mount("#the-app");VUEDA's controls, widgets, tooltips, and confirmation dialogs are first-party components, so there are no third-party UI plugins, services, or directives to register here. The toast surface is mounted as a component in your root template rather than registered as a plugin; see Toast Notifications below.
The sections below explain each registration step.
Theme
Importing @vueda/theme/vueda-tailwind/index.js registers all built-in component defaults; no setTheme call is needed. For alternative loading paths and when to apply project patches, see How the theme is registered.
VUEDA ships a first-party Tailwind CSS theme at @vueda/theme/vueda-tailwind/index.js. This is the recommended starting point. It maps each component's named slots to Tailwind utility classes and supports patches through patchTheme() and per-component themeOverride props. For an explanation of the available customization scopes, see Theming and Customization; for concrete recipes, see Customize VUEDA Appearance.
Using the vueda-tailwind theme requires Tailwind CSS to be set up in your project so those utility classes generate CSS. Install Tailwind CSS 4 (tailwindcss) and @tailwindcss/vite as dev dependencies and add the plugin to your vite.config.js:
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [vue(), tailwindcss()],
// ...
});The theme also requires a set of CSS custom properties that the class strings reference: semantic color tokens (--foreground, --background, --primary, --muted, --sidebar and related variants), VUEDA-specific dimensional tokens (--vueda-control-height, --vueda-control-radius, --vueda-cal-day, --vueda-sidebar-width, etc.), shadow tokens (--vueda-shadow-popover, --vueda-shadow-overlay), and motion tokens (--vueda-duration-interaction, --vueda-ease-interaction). The full set with default values is shipped at @vueda/theme/vueda-tailwind/base.css. Import it once in your project's main CSS file:
@import "tailwindcss";
@import "@vueda/theme/vueda-tailwind/base.css";base.css is the brand-customization surface. Override individual tokens after the import to re-skin the app; see Customize VUEDA Appearance for the full recipe. The default values land VUEDA in a near-monochrome cool-neutral palette with dense control sizing; consumers who want a different look should override tokens rather than fork base.css.
base.css names its fonts, IBM Plex Sans and JetBrains Mono, but does not load them. Load those families yourself or point the font tokens at fonts your app already loads; see Load or replace the fonts.
The theme system itself is CSS-framework-agnostic. setTheme accepts any object that follows the ThemeObject shape (component name to slot to class map). To use a different CSS framework, provide a theme object that maps the same component and slot keys to your own classes, and either supply your own equivalent token definitions or rewrite the class strings to not depend on the VUEDA tokens.
When installing your own theme object, call setTheme after the built-in defaults you intend to replace have registered and before those components render. It replaces the whole registry, including any earlier patches.
What depends on it: Themed components resolve their slot classes from the registry. Built-in components import their own theme modules, so they receive defaults even without the aggregate import or a setTheme call.
What fails without CSS: Registered class names have no styling effect unless the corresponding CSS is generated and loaded. Keep Tailwind and base.css in the application stylesheet.
Register the Icons
VUEDA components look up their icons in the Icon Registry. The registry starts empty, and a lookup for an icon that nobody registered returns no icon. Register icons before the app mounts.
The Font Awesome Free preset registers an icon for every name that the built-in components use. Install its packages:
pnpm add @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/vue-fontawesomeThen install the preset in main.js. Font Awesome adds its stylesheet at runtime by default. Import the stylesheet yourself and turn off the runtime stylesheet:
import { config as faConfig } from "@fortawesome/fontawesome-svg-core";
import "@fortawesome/fontawesome-svg-core/styles.css";
import { installFontAwesomeFreeIcons } from "@vueda/theme/vueda-tailwind/icons/fontAwesomeFree.js";
faConfig.autoAddCss = false;
installFontAwesomeFreeIcons();To use another icon library, pass your own registry to setIcons(). A registry maps a component name to its icon names, and each icon name to a { component, props } entry. Entries under the Default key apply to every component. patchIcons() merges a partial registry over the current one. The fontAwesomeFreeIcons export of @vueda/theme/vueda-tailwind/icons/fontAwesomeFree.js lists every name that the built-in components look up.
CRUDL Adapters
setupDefaultListCrud() and setupDefaultObjectCrud() register the HTTP adapter functions that VUEDA's composables use for every data operation (list, retrieve, create, update, patch, delete, bulk delete).
These must be called before any VUEDA store or composable attempts a data fetch. Calling them before createApp satisfies this requirement.
What depends on them: Every list view (ViewList, filtering, pagination), every detail view (ViewRead, ViewCreate, ViewUpdate, ViewDestroy), and any composable that calls the CRUDL layer.
What fails without them: Data operations silently return no results. Lists appear empty, forms do not load data, and save operations have no effect. There is no runtime error; the CRUDL layer has no adapter to call, so it produces no output.
Controls and Widgets
VUEDA's controls and widgets (Button, WidgetSelectDropdown, WidgetDateField, WidgetTextInput, WidgetCombobox, WidgetCheckbox, WidgetRadioGroup, WidgetRangeSlider, and others) are first-party components built on Reka UI, which VUEDA bundles. There is no third-party component-library plugin to register: these components import their defaults and resolve classes from the theme registry. The remaining setup steps cover the toaster surface, which is mounted as a component rather than registered as a plugin.
Toast Notifications
Toast notifications are backed by @arrai-innovations/vue-sonner. Import toast from that package name, not from upstream vue-sonner, so your application code and VUEDA's toaster share the same module instance. No plugin registration is needed; toast is a plain module import that works anywhere (components, composables, stores, route guards).
Setup: Mount the Sonner toaster once in your root component (e.g. TheApp.vue):
<script setup>
import Sonner from "@vueda/feedback/toast/Sonner.vue";
</script>
<template>
<RouterView />
<Sonner />
</template>Usage:
import { toast } from "@arrai-innovations/vue-sonner";
toast.success("Saved successfully");
toast.error("Something went wrong", { description: "Details here", duration: 15000 });
toast.warning("Please check your input");
toast.info("No changes detected");What depends on it: ActionForm displays success, error, and warning toasts after form submissions, including for ViewExecuteTransition's workflow-transition submissions, which run through the same ActionForm shell. AuthorizingForm shows a redirect confirmation toast. useObjectForm default handlers show toasts for "No Changes Detected", "Pre-save Validation Failed", and "Save Validation Failed" scenarios. ClickToCopyText and the MFA setup views also use toast notifications.
What fails without it: If the Sonner toaster is not mounted, toast(...) calls silently do nothing (no error is thrown, but no notification appears).
Confirmation Dialogs
Confirmation is built into VUEDA's forms; there is no global service to register. Forms that can prompt for confirmation (for example, ActionForm and the object-form flows) render their own FormConfirmDialog and drive it through the per-form controller returned by useConfirmationController. When a submission returns warnings that require confirmation, the form opens its dialog and resolves once the user responds.
What depends on it: ActionForm and the destroy and update flows prompt for confirmation when an action is configured to require it or when the server returns confirm-then-save warnings (HTTP 409).
What fails without it: Nothing to register, so nothing fails at setup time. If you build a fully custom submit surface that bypasses the built-in dialog, the controller fails closed: it logs a console warning and treats the submission as cancelled rather than leaving it pending. Render <FormConfirmDialog :controller="..." /> (or register a custom consumer via confirmation.register()) so the submission can be confirmed.
Tooltips
Tooltips are first-party components built on Reka UI, not a registered directive. The shell layer (for example, SidebarProvider) wraps the relevant subtree in a TooltipProvider, and components render the Tooltip component where hover explanations are needed. There is no v-tooltip directive to register and nothing to install.
What depends on it: Field help text, icon labels, and abbreviated content render tooltips for hover explanations.
What fails without it: Nothing to register. Tooltips appear wherever a TooltipProvider is present in the component tree above them, which the built-in shell components provide.
Verification Checklist
After completing the registration sequence, verify the following:
- A list view loads data and renders rows with correct styling.
- Submitting a form displays a success toast notification.
- A form with invalid data displays inline validation errors and a warning toast.
- Hovering over a field with help text shows a tooltip.
- A destructive action (e.g., delete) shows a confirmation dialog before proceeding.
Troubleshooting
Toast notifications not appearing. The Sonner toaster is not mounted in the root component. Add <Sonner /> to TheApp.vue.
Components render as unstyled HTML. Built-in components register their own defaults; omitting setTheme does not leave them unstyled. Verify that the application loads its stylesheet, that it imports Tailwind and @vueda/theme/vueda-tailwind/base.css, and that the Tailwind Vite plugin generates CSS for the theme classes. If slot classes are missing from the element, check whether a later setTheme call replaced the registry with an incomplete theme.
Text renders in a system font, and headers wrap where the component reference does not. The page loads no face with the family name in --vueda-font-sans or --vueda-font-mono, so the browser used a fallback. Load the default fonts or override the stacks; see Load or replace the fonts.
Lists load but show no data. CRUDL adapters are not registered. Verify that setupDefaultListCrud() and setupDefaultObjectCrud() are called before app creation. Check the network tab; if no HTTP requests are made for list data, the adapter layer has no implementation.
Tooltips do not appear on hover. No TooltipProvider is present above the component in the tree. The built-in shell components provide one; if you render tooltip-bearing components outside that shell, wrap them in a TooltipProvider.
Confirmation dialog does not appear for an action. The action is not configured to require confirmation, or a fully custom submit surface bypasses the built-in FormConfirmDialog. Verify the action's configuration requires confirmation, and that any custom form renders FormConfirmDialog (or registers a consumer on the confirmation controller).
Relevant Implementation Surface
- JavaScript:
- Vue.js Components: