Skip to content

Golden Path β€” Widgets ​

Widgets are how your plugin appears in the workbench composition editor and in the running app. Raclette enforces a folder contract; everything inside the Vue component is up to you (see Vue structure).

For usePluginApi, i18n, and generated-config, see How to use β€” not repeated here.

Folder contract (required) ​

PieceRule
Pathfrontend/widgets/<WidgetFolder>/
Component<WidgetFolder>Widget.vue (name must end with Widget.vue)
Catalogsetup.ts with details + config

Full plugin tree (atoms diagram):

exampleCreator__examplePlugin/
β”œβ”€β”€ raclette.plugin.ts            # Main plugin configuration 
β”œβ”€β”€ frontend/                     # Frontend-side code (if frontendDir specified)
β”‚   β”œβ”€β”€ [...]                     # See plugin metadata for more
β”‚   └── widgets/                  # Plugin widgets
β”‚       β”œβ”€β”€ Example/           # Your custom Widget folder name 
β”‚       β”‚   β”œβ”€β”€ ExampleWidget.vue    # The widget File. Needs to follow this structure "[CustomName]Widget.vue"
β”‚       β”‚   β”œβ”€β”€ setup.ts          # Contains details and config for the widget
β”‚       β”‚   └── [...] 
β”‚       └── [...] 
└── backend/                      # Server-side code (if backendDir specified)
    β”œβ”€β”€ index.ts                  # Server entry point
    β”œβ”€β”€ example.model.ts     # The model for your dataType. Currently mongoose
    β”œβ”€β”€ example.schema.ts    # The schema for your dataType. Fastify schema, validations etc
    β”œβ”€β”€ example.service.ts   # The services for your dataType ie the actuall backend business logic         
    β”œβ”€β”€ routes/                   # API routes
    └── helpers/                  # Business logic helpers and utils

Details of raclette.plugin.ts

setup.ts (required shape) ​

typescript
import type { WidgetDeclaration } from "@raclettejs/core"

export const details = {
  title: "My Example Widget",
  color: "#6CB5D1",
  icon: new URL("./icon.svg", import.meta.url).href,
  images: [new URL("./screenshot.png", import.meta.url).href],
  description: "An example widget",
} satisfies WidgetDeclaration

const config = {}

export default {
  config,
  details,
}

Add config entries with Vue PropType and an editor block so workbench admins can tune props without redeploying.

*Widget.vue β€” entry file only ​

The widget file should wire the feature: usePluginApi(), props, i18n, and child components. Move presentation to components/ and logic to composables/ when the widget grows.

Fuller template: Widget Vue entry β€” cooking step.

Props from the orchestrator ​

SourceRole
Workbench config / publicFrom setup.ts editors
slotParamsFrom URL for this slot β€” declare matching prop names
ContextcompositionName, slotType, uuid

You do not parse the URL manually for standard params; see Reading URL state.

Test in workbench ​

  1. yarn dev with workbench (local URLs).
  2. Compositions β€” add your widget to a layout.
  3. Interaction links β€” deep links with query params.
  4. Open the portal frontend on the resulting URL.

If the widget is missing from the picker: check folder name, *Widget.vue suffix, and plugin load (npm or local plugins/).

Loading (framework-internal) ​

Raclette detects when widget slots have rendered (including async chunk loads) before revealing content. You do not need to call readiness hooks, set data attributes, or branch on slotType.

SurfaceWhat you see
Page navigationTop progress bar; page content stays hidden until slots are ready
ModalLocal loading overlay on the modal until modal slots are ready
Inline (app bar, user menu)No global loading β€” widgets load in place

Widget-owned loading UI inside the slot (skeletons, spinners) is fine and does not replace the framework overlay or progress bar.

Failed widgets do not block the page ​

If a widget fails to load or throws during setup, raclette renders ErrorWidgetState in that slot. The slot is treated as ready so navigation loading and modals are not stuck waiting on a broken widget. Other widgets on the same page still load normally.

Fix the plugin error and refresh; you do not need to change orchestrator code for this behavior.

See also ​