Skip to content
Guide

Add a Slot Widget

Fill a platform-owned Shell slot with an App component, a versioned props contract, and a permission-gated descriptor.

Place an App component inside a host-owned surface. The People employment card is a working example: it fills profile.self.employment, reads the signed-in worker through an authorized API, and uses ProfileSlotPropsV2.

Connect component and descriptor

Start with a working App frontend from Build an App screen. Then connect three pieces:

  1. Implement the component against the slot's published SDK props. People reads props.workContext?.ref, includes it in queryKeys.profileSelfProjection(...), and passes work_context_ref to /people/me. Without a work-context ref it renders a context-required empty state and does not fetch. The API resolves the signed-in worker; never accept a browser-selected target worker as authority.
  2. Register the component name through the App frontend entry. packages/people/resources/js/index.ts includes PeopleEmploymentProfileWidget in autoRegisterPackageSurfaces({ overrides: ... }), loading ./profile/PeopleEmploymentProfileWidget.
  3. Return this descriptor from an AppDescriptorContribution under the manifest's contribution locations. It is the actual entry in packages/people/src/Descriptors/PeopleCoreSlotWidgets.php:
Code example
PHP
new \Nexia\AppDescriptors\SlotWidgetDescriptor(
    key: 'people.self.employment.profile',
    version: '1.0',
    slot: 'profile.self.employment',
    component: 'PeopleEmploymentProfileWidget',
    slotApiVersion: 2,
    status: \Nexia\AppDescriptors\DescriptorStatus::Active,
    permission: 'people.worker_profile.read',
    sort: 10,
    labelKey: 'people.worker_profile.widget.title',
    familyKey: 'people.self.employment',
);

Refresh discovery after adding the contributor:

Code example
Shell
task artisan -- nexia-runtime:generate-app-map
task artisan -- nexia-runtime:refresh-runtime-caches

Build and activate the changed frontend using the package workflow from Create an App Package. The descriptor's permission filters placement; the read endpoint must independently authorize the request.

Confirm the result

Open My Profile's employment tab in an operational People tenant with the read permission and a valid work context. The card should render the current worker's employment. Check missing context, loading, empty data, ordinary network failure, and revoked access. After authority is revoked, do not keep rendering cached protected data as a successful result.

packages/people/resources/js/profile/PeopleEmploymentProfileWidget.tsx is the complete adapter, including retry and stale-data handling. The package doctor checks page-component pairing, so opening the actual slot is still necessary to prove widget registration. Follow Test an App for automated package checks.

Choose the right slot and version

The current profile host accepts these slot keys and props versions. Use V2 for new widgets; V1 support is retained only for existing widgets in the listed slots.

Slot keyHost surfaceProps versions
profile.self.overviewOverview1, 2
profile.self.employmentEmployment1, 2
profile.self.organizationOrganization2
profile.self.time_leaveTime and leave1, 2
profile.self.payPay1, 2
profile.self.projectsProjects1, 2
profile.self.growthGrowth1, 2
profile.self.documentsDocuments2
approval.composer.business_formApproval business form2

Profile slots use ProfileSlotPropsV2. The Approval row describes the current composer, which supplies ApprovalBusinessFormSlotPropsV2 and resolves widgets through approvalComposerBusinessFormRegistry by the binding’s formWidgetKey; it does not use the profile component registry. See Electronic Approval for that registration path.

The profile version matrix is defined in app/Shell/Profile/ProfileSlotContract.php; the Approval props and registry are defined in resources/js/core/approval/approval-composer-business-form.ts.

ChoiceMeaning
slotExisting host slot; the App cannot create a new slot by naming one
slotApiVersionSDK props contract implemented by the component
versionThe widget descriptor's own version
componentExact registered frontend key
sort, familyKeyOrdering/grouping; neither grants access

Read slot props through React components and hooks. A profile card, Approval business form, and Process user-task form have different contracts. For Approval use Electronic Approval; for user-arranged placement use Add a Dashboard Widget.

Change props and slotApiVersion together. Preserve descriptor identity for existing references; deprecate before removal. Import only SDK types and host facades, and request a platform contract change when the published props do not carry the required context.

Source of truth: docs/developers/content/en/platform-extensions/add-slot-widget.md