Skip to content

3. Renderer registrations

Every UI extension point is a field on your Renderer.LensExtension subclass. This page documents the shape of each registration type and where it renders. All components.* fields take React.ComponentType.

Common conventions:

  • visible?: IComputedValue<boolean> — MobX-reactive show/hide.
  • priority?: number / orderNumber?: number — ordering (default 50 where used).
  • apiVersions: string[] + kind: string — match against a k8s object/entity.
  • id?: string — usually optional; auto-derived when omitted.

3.1 Pages

interface PageRegistration {
  id?: string;                    // unique per extension; part of the URL
  params?: PageParams;            // typed page URL params
  components: { Page: React.ComponentType<any> };
  enabled?: IComputedValue<boolean>;
}

interface PageTarget {
  extensionId?: string;
  pageId?: string;
  params?: PageParams;
}
  • globalPages render in the root frame (no cluster context).
  • clusterPages render inside a cluster frame, alongside the cluster sidebar.

A page is reached via a sidebar menu entry (clusterPageMenus) whose target points at the page id, or programmatically via navigation.

3.2 Cluster sidebar menu

interface ClusterPageMenuRegistration {
  id?: string;
  parentId?: string;              // nest under another menu item to make a sub-item
  target?: PageTarget;            // page to navigate to on click
  title: React.ReactNode;         // source type is StrictReactNode, not plain string
  components: { Icon?: React.ComponentType<IconProps> | null };
  visible?: IComputedValue<boolean>;
  orderNumber?: number;
}

Example (from the example extension):

clusterPageMenus = [{
  id: "example",
  title: Example.crd.title,
  target: { pageId: "example" },
  components: { Icon: ExampleIcon },
}];

3.3 Always-mounted cluster components

interface ClusterFrameChildComponent {
  id: string;
  Component: React.ElementType;
  shouldRender: IComputedValue<boolean>;
}

Use for dialogs/overlays that must exist regardless of the current page.

3.4 Preferences

interface AppPreferenceRegistration {
  title: string;
  id?: string;
  showInPreferencesTab?: string;   // target a tab by id
  components: {
    Hint: React.ComponentType<any>;
    Input: React.ComponentType<any>;
  };
}

interface AppPreferenceTabRegistration {
  title: string;
  id: string;
  orderNumber?: number;
  visible?: IComputedValue<boolean>;
}

appPreferences adds a control block; appPreferenceTabs adds a whole tab to the Preferences window. The Input component typically binds to an ExtensionStore observable.

3.5 Entity settings

interface EntitySettingRegistration {
  apiVersions: string[];
  kind: string;
  title: string;
  components: { View: React.ComponentType<{ entity: CatalogEntity }> };
  source?: string;
  id?: string;                     // default btoa(title)
  priority?: number;               // default 50
  group?: string;                  // default "Extensions"
}

Adds a settings pane for a catalog entity — e.g. a per-cluster settings page.

3.6 Status bar

interface StatusBarRegistration {
  components?: {
    Item: React.ComponentType<StatusBarItemProps>;   // StatusBarItemProps = {}
    position?: "left" | "right";                      // default "right"
  };
  visible?: IComputedValue<boolean>;
  item?: React.ReactNode | (() => React.ReactNode);   // @deprecated, use components
}

3.7 Kube object detail panels

interface KubeObjectDetailRegistration<T extends KubeObject = KubeObject> {
  kind: string;
  apiVersions: string[];
  components: { Details: React.ComponentType<KubeObjectDetailsProps<T>> };
  priority?: number;
  visible?: IComputedValue<boolean>;
}

interface KubeObjectDetailsProps<T extends KubeObject> {
  className?: string;
  object: T;
}

Adds a panel to the details drawer of any k8s object matching kind + apiVersions. Your Details component receives the object as props.object. Example:

kubeObjectDetailItems = [{
  kind: Example.kind,
  apiVersions: Example.crd.apiVersions,
  priority: 10,
  components: {
    Details: (props: Renderer.Component.KubeObjectDetailsProps<any>) =>
      <ExampleDetails {...props} extension={this} />,
  },
}];

3.8 Kube object menu items

interface KubeObjectMenuRegistration<Props extends KubeObjectMenuItemProps = any> {
  kind: string;
  apiVersions: string[];
  components: { MenuItem: React.ComponentType<Props> };
  visible?: IComputedValue<boolean>;
}

interface KubeObjectMenuItemProps<Object extends KubeObject = KubeObject> {
  object: Object;
  toolbar?: boolean;
}

Adds action items to an object's context/action menu.

3.9 Kube object context-menu handlers

For dynamic menu items (computed when the menu opens):

type KubeObjectHandlerRegistration = { apiVersions: string[]; kind: string }
  & RequireAtLeastOne<{ onContextMenuOpen: KubeObjectOnContextMenuOpen }>;

// KubeObjectOnContextMenuOpen is the FUNCTION type; its argument is typed
// KubeObjectOnContextMenuOpenContext:
type KubeObjectOnContextMenuOpen = (ctx: KubeObjectOnContextMenuOpenContext) => void;

interface KubeObjectOnContextMenuOpenContext {
  readonly menuItems: IObservableArray<KubeObjectContextMenuItem>;
  navigate: (location: string) => void;
}

interface KubeObjectContextMenuItem {
  id?: string;
  icon: string | BaseIconProps;   // string = Material icon name shorthand
  title: string;
  onClick: (obj: KubeObject) => void;
}

Push items into ctx.menuItems when the menu opens.

3.10 Workloads Overview sections

interface WorkloadsOverviewDetailRegistration {
  components: { Details: React.ComponentType<{}> };
  priority?: number;
  visible?: IComputedValue<boolean>;
}

3.11 Command palette

interface CommandRegistration {
  id: string;                                        // globally unique
  title: string | ((ctx: CommandContext) => string);
  action: (ctx: CommandActionContext) => void;
  isActive?: (ctx: CommandContext) => boolean;       // default () => true
  scope?: "global" | "entity";                       // @deprecated, use isActive
}

interface CommandContext { readonly entity: CatalogEntity }
interface CommandActionContext extends CommandContext {
  navigate: (url: string, opts?: { forceRootFrame?: boolean }) => void;
}

3.12 Welcome menu

interface WelcomeMenuRegistration {
  title: string | (() => string);
  icon: string;
  click: () => void | Promise<void>;
}

3.13 Catalog entity detail panels

interface CatalogEntityDetailRegistration<T extends CatalogEntity> {
  kind: string;
  apiVersions: string[];
  components: { Details: React.ComponentType<{ entity: T }> };
  priority?: number;
}

3.14 Top bar

interface TopBarRegistration {
  components: { Item: React.ComponentType };
}

3.15 Catalog category columns and views

interface CategoryColumnRegistration {
  priority?: number;                                    // default 50
  id: string;                                           // unique to your extension
  renderCell: (entity: CatalogEntity) => React.ReactNode;
  titleProps: { className?: string; title: React.ReactNode; "data-testid"?: string };
  sortCallback?: (entity: CatalogEntity) => string | number | (string | number)[];
  searchFilter?: (entity: CatalogEntity) => string | string[];
}

interface AdditionalCategoryColumnRegistration extends CategoryColumnRegistration {
  kind: string;    // e.g. "KubernetesCluster"
  group: string;   // e.g. "entity.k8slens.dev"
}

interface CustomCategoryViewRegistration {
  kind: string;
  group: string;
  priority?: number;                                    // default 50
  components: { View: React.ComponentType<{ category: CatalogCategory }> };
}

additionalCategoryColumns adds columns to an existing category list; customCategoryViews replaces the whole view for a category.


Note: two registrations that do NOT exist

Older Lens tutorials mention kubeObjectStatusTexts and kubeObjectListLayoutColumns. These are not present in this Freelens version — do not use them. To add columns to a resource list, render your own KubeObjectListLayout inside a clusterPage (see Kubernetes API).