Extending Rebase
Overview
Section titled “Overview”Rebase offers roughly a dozen extension mechanisms — plugins, slots, component overrides, entity views, actions, custom fields, and more. Each one targets a different scope (app-wide, per-collection, per-entity, per-property) and a different part of the UI.
This guide helps you pick the right mechanism for your use case, then links to the detailed reference for each.
Everything here is the admin panel. For the server — narrowing a read,
adding a route, embedding the driver in your own process, rebase eject — see
Rebase doesn’t do X, which is the same kind of table
for the backend.
Decision Table
Section titled “Decision Table”| I want to… | Mechanism | Scope | Reference |
|---|---|---|---|
| Replace the app bar | components (Shell.AppBar) |
app | Component Overrides |
| Replace the login page | components (Auth.LoginView) |
app | Component Overrides |
| Replace the home page | components (HomePage) |
app | Component Overrides |
| Change how one collection’s form looks entirely | formView |
collection | below |
| Swap one component inside one collection | collection.components |
collection | Component Overrides |
| Set default component overrides for all collections | components (collection-scoped names) |
app | Component Overrides |
| Add a button to the collection toolbar | collection Actions |
collection | Entity Actions |
| Inject UI at a collection toolbar slot | collection.actions slot |
app/plugin | Slots |
| Add a computed column to a table | additionalFields |
collection | Additional Columns |
| Add a custom field widget for a property type | propertyConfigs |
property type | Custom Fields |
| Add an entity tab | entityViews |
entity | Entity Views |
| Render one collection’s rows a different way | admin.customViews |
collection | below |
| Add a row/context action or entity button | entityActions |
entity | Entity Actions |
| Put a figure on a collection’s home-page card | home.card.widget slot |
app/plugin | Slots |
| Inject UI at a specific chrome location | slots |
app/plugin | Slots |
| Ship several extensions as one installable unit | plugins |
app | Plugins |
| Style the thing I just built | @rebasepro/ui + theme tokens |
any | Styling Custom UI |
Mechanisms in Detail
Section titled “Mechanisms in Detail”Plugins
Section titled “Plugins”Scope: app.
A plugin bundles collections, views, component overrides, slot contributions, auth, data sources, providers, hooks, and lifecycle callbacks into a single installable unit. All other mechanisms listed here can be contributed through a plugin’s interface.
Scope: app (contributed per-slot).
Slots are named UI extension points scattered throughout the CMS chrome. You register a React component targeting a slot name, and it renders at that location. There are 27 slots covering the home page, navigation, collection views, forms, entity rows, form fields and the app bar — and every one of them is rendered.
Component Overrides (Swizzling)
Section titled “Component Overrides (Swizzling)”Scope: app-level defaults or per-collection.
Two modes: Eject (full replacement) or Wrap (augment the original).
19 overridable component names in two tiers:
App-only (7):
Shell.AppBarShell.DrawerShell.DrawerNavigationItemShell.DrawerNavigationGroupHomePageHomePage.CollectionCardAuth.LoginView
Collection-scoped (12):
Collection.ViewCollection.TableCollection.CardCollection.EmptyStateCollection.ActionsCollection.FilterFieldEntity.FormEditView.FormActionsDetailViewEntity.SidePanelEntityPreviewEntity.MissingReference
Precedence: Collection-level components override app-level defaults for the same component name (simple object spread — collection values overwrite global values). App-only component names (Shell.*, HomePage, Auth.*) can only be overridden at the <Rebase> level.
Entity Views
Section titled “Entity Views”Scope: entity (adds tabs).
Custom views that appear as tabs in the entity detail page. Can be defined globally on <Rebase> or per-collection.
Entity Actions
Section titled “Entity Actions”Scope: entity.
Custom action buttons on individual entities (publish, archive, clone, etc.). Can be defined globally or per-collection.
Collection Actions
Section titled “Collection Actions”Scope: collection.
Toolbar-level React components that receive CollectionActionsProps (selected entities, table controller, collection context). Rendered in the collection toolbar alongside built-in actions.
Relationship with collection.actions slot: Both are additive — Actions components render first in the toolbar, then slot contributions from collection.actions. They do not replace each other.
→ Entity Actions — Collection Actions
Custom view modes
Section titled “Custom view modes”Scope: collection (adds a view mode).
A map, a calendar, a gallery, a timeline — another rendering of the same rows, offered in the collection’s view switcher beside List, Table, Cards and Board.
// collection configadmin: { customViews: [ { key: "map", name: "Map", icon: "Map", Builder: MapView } ], enabledViews: ["table", "map"], defaultViewMode: "map"}Or register the component once and name it by key, which is also what makes it selectable from the collection editor:
<RebaseCMS collections={collections} collectionViews={[{ key: "map", name: "Map", icon: "Map", Builder: MapView }]}/>admin: { customViews: ["map"] }Builder receives the live tableController, so the view inherits the
collection’s filters, the search box, sorting, pagination, permission checks
and the entity side panel — that is the whole reason to declare one instead of
building an AppView:
function MapView({ tableController, onEntityClick }: CollectionCustomViewParams) { return <MapCanvas markers={tableController.data.map(e => e.values.location)} onMarkerClick={i => onEntityClick?.(tableController.data[i])} />;}Choosing the view updates ?__view=, survives a reload, and persists per user.
Declaring one is enough to offer it — enabledViews only needs setting when you
want to take built-ins away. With a single entry the switcher is hidden.
This is not a way to build a view spanning several collections. A view mode
is another rendering of one collection’s query. If your component ignores
tableController and fetches four tables of its own, it wants to be an
AppView — the toolbar above it, with its search
box and its record count, would be describing a query it does not render.
formView
Section titled “formView”Scope: collection.
Replaces the entire default entity form with a custom component. Set on a collection definition:
const collection = { slug: "products", admin: { formView: { Builder: MyCustomProductForm, includeActions: true // Save and Discard in the bar (default: true) } }};Use when you need a completely custom layout for one collection’s entity editing experience. For smaller tweaks, prefer collection.components with Entity.Form override instead.
The Builder is rendered inside the record’s form and receives its live formContext: write with formContext.setFieldValue, and the bar’s Save stores the record. Where the record cannot be edited — the read-only detail view, or a user without edit permission — formContext.disabled is true and writes throw. Set includeActions: false if your Builder saves on its own through formContext.submit().
additionalFields
Section titled “additionalFields”Scope: collection.
Computed/virtual columns displayed in the collection table. These don’t correspond to stored properties — they’re calculated at render time.
propertyConfigs
Section titled “propertyConfigs”Scope: property type.
Custom field widgets for specific property types, providing custom form fields and preview components.
Not the admin panel
Section titled “Not the admin panel”If the thing you want to change is what the server does rather than what the panel shows, this is the wrong page. The server has its own ladder:
| I want to… | Rung | Reference |
|---|---|---|
| Narrow which rows a read returns | beforeQuery callback |
Extending the server |
| Redact a value on the way out | afterRead callback |
Callbacks |
| Add an endpoint of my own | custom function | Custom Functions |
| Make search find substrings and fold accents | search.mode: "hybrid" |
Search |
| Own the server process | custom server, then rebase eject |
Extending the server |
Precedence Summary
Section titled “Precedence Summary”collection.componentsapplies over globalcomponentsinside that collection. A collection replacement replaces both; Since 0.25 a collectionwrap: trueoverride wraps the global override when there is one (on 0.24 it wraps the built-in, and the global override is skipped). See Component Overrides.- Collection
Actionsandcollection.actionsslot are additive —Actionsrender first, then slot contributions. - Collection-level
entityActionsandentityViewsextend (not replace) global ones. - Plugins apply in the order of the
pluginsarray, not bykey. Slot contributions render by theirorder(lower first, 50 by default), and ties keep that order. Since 0.25 Field wrappers from several plugins compose in that order, the first plugin’s innermost; on 0.24 only the last wrapper rendered. See Plugins.