Developer docs/Guides
Addon UI
Addons add UI without shipping JavaScript to the main app. There are three ways to do it:
- Native pages (
ui.pages[].body): a JSON tree of shadcn components that the frontend renders. The allowed node types and their fields are in the UI schema. - Iframe pages (
ui.pages[].frame): a sandboxed HTML file from the addon'sassets/. This needs"iframe"incapabilities.ui, and the admin must approve it explicitly at install. - Slots (
ui.slots[]): small contributions in named places of existing pages, such as a toolbar, the dashboard or the layout banner.
#Example
Strings that start with plugin.<addon-id>. are translated from the manifest's i18n map. {{data.<name>}} reads a data source declared in data, and {{row.<field>}} reads the current table row.
#Slots and positions
Every page and its exact slot names are listed in Widgets and slots.
Positions an addon can fill on every page. A slot name is <area>.<route>.<position>: area is admin or client, route is the page's route key (path segments without ids joined by -, e.g. /admin/invoices/42 → invoices, /admin/settings/tax → settings-tax) or * for every page. replace:<section> swaps out a named section.
| Kind | Values |
|---|---|
| Page positions | before, after, toolbar, row-actions, tabs, detail-panel |
| Layout positions | header, sidebar, footer, banner |
Slots a plugin can fill with a node tree. Context keys available as {{ctx.*}} are listed next to each slot.
| Slot | Context keys |
|---|---|
admin.dashboard | |
client.dashboard | |
admin.service.detail | ctx.service_id |
admin.customer.detail | ctx.customer_id |
admin.order.detail | ctx.order_id |
admin.invoice.detail | ctx.invoice_id |
client.home |