Widget Catalog

The Widget Catalog provides a browsable and searchable list of all available widgets that can be added to your layouts. It is accessible from the editor sidebar and through the Widget Selection Modal.

Overview

Widgets are organized into categories (e.g., Content, Data, Layout). Each widget entry displays its title and, optionally, an expandable description to help you identify the right widget for your use case.

Searching for Widgets

You can filter the displayed widgets by typing in the search box at the top of the catalog or modal.

  • Matches against: widget title and widget description.
  • Case-insensitive: the search is not case-sensitive.
  • Live filtering: results update as you type β€” no need to press Enter.
  • Empty query: when the search box is empty, all widgets are shown grouped by category.
  • No results: if no widgets match your query, an empty state message is displayed.

Widget Catalog (Sidebar)

The search input is located at the top of the sidebar panel.

[ πŸ” Search... ]

Layout
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Container  β”‚  β”‚    Grid     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Content
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚    Text     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

When you begin typing, categories with no matching widgets are hidden automatically. Clearing the search box restores the full list.

Expanding a widget's description (via the info button) is reset each time you type a new search term.

Widget Selection Modal

The search input appears below the modal header, above the widget grid.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Select a Widget               [ βœ• ]    β”‚
β”‚  [ πŸ” Search...                      ]  β”‚
β”‚                                          β”‚
β”‚  Layout                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚Container β”‚ β”‚  Grid    β”‚ β”‚  ...     β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

When the modal is closed (either by selecting a widget or pressing the close button), the search query is automatically cleared so the next time it opens the full list is shown.

How Filtering Works

Filtering is performed by the shared getFilteredWidgetsByCategory function in widget-registry.ts. It:

  1. Iterates over all registered widget categories.
  2. For each category, retains only widgets that are marked visibleInCatalog.
  3. If a search query is present, further filters to widgets whose translated title or description contains the query string.
  4. Excludes categories that have no matching widgets from the result.

Because the result is derived reactively from the search query state, the UI updates automatically as the user types.

Third-Party Web Component Entries

In addition to the code-registered widgets, the catalog dynamically lists the current project's active web component registrations (see the web component registry). Each entry uses the registration's title and category and β€” when placed β€” creates a WebComponent widget preconfigured with that registration's id. The component then renders inside the sandboxed iframe via the host bridge. Building and registering your own components is covered in the Web Components docs (authoring, permissions, security model, consent, and theming).

  • Only registrations with status active appear; draft and disabled registrations are hidden.
  • A registration with an unknown category is listed under Content.
  • Search matches the registration title, like any other widget.
  • Placed widgets of a registration that is later disabled render a neutral placeholder instead of loading any third-party code.
  • Before any third-party code runs, each user sees a consent overlay stating that this is a third-party component smallstack is not responsible for, listing the permissions the component declared. Only after accepting does the sandbox load. Consent is per user, per registration and per bundle version and per declared permission set β€” uploading a new bundle version or changing the registration's permissions re-prompts every user. For logged-in users the consent is recorded server-side; anonymous application visitors keep it in their browser's localStorage.

The merging is performed by mergeWebComponentCatalogEntries in packages/client/src/web-components/web-component-catalog.ts on top of the filtering described above.

Datatype bindings at placement time

A registration's collection scopes (collection:{configurationProperty}:{action}) name a property of the widget's placement configuration β€” not a concrete datatype. When a placed WebComponent widget is edited, the widget properties form expands each declared configuration property into a datatype picker (under "Data bindings"), so the editor binds the concrete datatype there. The picker stores the bare type id, which server-side scope resolution (mapScopeToRLSPermission) maps onto the platform's RLS permissions. Without a binding, the scope is simply not granted and the consent overlay falls back to showing the raw configuration property name.

Attributes

Attribute Description
data-testid="widget-catalog-search" Test ID for the search input in the Widget Catalog sidebar.
data-testid="widget-selection-search" Test ID for the search input in the Widget Selection Modal.
data-testid="catalog-widget-web-component-{registrationId}" Test ID of a dynamic web component catalog entry.
data-testid="web-component-widget" Root of a placed WebComponent widget.
data-testid="web-component-widget-placeholder" Neutral placeholder shown for disabled/missing registrations.
data-testid="web-component-widget-loading" Skeleton shown while the registrations collection does its initial sync.
data-testid="web-component-consent-overlay" Consent overlay blocking the sandbox until accepted.
data-testid="web-component-consent-permission" One disclosed permission entry in the consent overlay.
data-testid="web-component-consent-no-permissions" Shown instead of the permission list when a registration declares none.
data-testid="web-component-consent-accept" Accept button of the consent overlay.