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:
- Implement the component against the slot's published SDK props. People reads
props.workContext?.ref, includes it inqueryKeys.profileSelfProjection(...), and passeswork_context_refto/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. - Register the component name through the App frontend entry.
packages/people/resources/js/index.tsincludesPeopleEmploymentProfileWidgetinautoRegisterPackageSurfaces({ overrides: ... }), loading./profile/PeopleEmploymentProfileWidget. - Return this descriptor from an
AppDescriptorContributionunder the manifest's contribution locations. It is the actual entry inpackages/people/src/Descriptors/PeopleCoreSlotWidgets.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:
task artisan -- nexia-runtime:generate-app-map
task artisan -- nexia-runtime:refresh-runtime-cachesBuild 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 key | Host surface | Props versions |
|---|---|---|
profile.self.overview | Overview | 1, 2 |
profile.self.employment | Employment | 1, 2 |
profile.self.organization | Organization | 2 |
profile.self.time_leave | Time and leave | 1, 2 |
profile.self.pay | Pay | 1, 2 |
profile.self.projects | Projects | 1, 2 |
profile.self.growth | Growth | 1, 2 |
profile.self.documents | Documents | 2 |
approval.composer.business_form | Approval business form | 2 |
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.
| Choice | Meaning |
|---|---|
slot | Existing host slot; the App cannot create a new slot by naming one |
slotApiVersion | SDK props contract implemented by the component |
version | The widget descriptor's own version |
component | Exact registered frontend key |
sort, familyKey | Ordering/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.