4.5 Implementing PCF Component Interfaces; Device, Utility & Web API Features
Key Takeaways
- context.parameters, context.mode, context.device, context.utility, context.webAPI, and context.factory are the sub-APIs exposed to a PCF component beyond its bound value.
- context.device covers hardware features (camera, barcode, GPS, file picker); context.utility covers metadata and the standard lookup dialog; context.webAPI mirrors Xrm.WebApi but is scoped to the component so it works identically in canvas apps.
- Every Device, Utility, or WebAPI capability used in code must first be declared in the manifest's <feature-usage> block or the call fails at runtime.
- Dataset paging (loadNextPage) lives on the bound dataset object, separate from context.factory.requestRender(), which re-invokes updateView().
- React-based components implement ReactControl and reference React as a platform-library resource rather than bundling their own copy, avoiding conflicting React instances.
The context object passed into init() and updateView() is more than just the bound field or dataset — ComponentFramework.Context<IInputs> bundles several sub-APIs that let a code component read platform metadata, call hardware features, and talk to Dataverse directly, all without depending on the host form's global Xrm object.
The Context Sub-APIs
| Sub-API | Purpose |
|---|---|
context.parameters | The bound value(s) — a single typed value with formatting/security metadata for field components, or the dataset object (records, columns, sortedRecordIds, paging) for dataset components |
context.mode | Read-only/disabled state, and allocatedWidth/allocatedHeight; trackContainerResize(true) opts the component into updateView() calls on resize |
context.device | Hardware capabilities: captureImage(), captureAudio(), captureVideo(), getBarcodeValue(), getCurrentPosition(), pickFile() |
context.utility | getEntityMetadata(), lookupObjects() (opens the standard lookup dialog), and formatting/parsing helpers |
context.webAPI | The same create/retrieve/update/delete operation surface as Xrm.WebApi, scoped for use inside the component |
context.factory | requestRender() to ask the platform to re-invoke updateView(), plus dataset helpers for adding records |
Why does a component reach for context.webAPI instead of the global Xrm.WebApi used in form scripting? Because a PCF component is designed to be portable — the same component can run inside a canvas app, where Xrm doesn't exist at all. Scoping data access, navigation, and utility helpers to context keeps the component's code identical regardless of host, which is exactly what makes PCF components reusable across model-driven and canvas apps rather than tied to one surface.
As covered in the previous section, every one of these capabilities — Device, Utility, WebAPI — must be declared in the manifest's <feature-usage> block before it is usable; calling context.device.getBarcodeValue() from a component whose manifest never declared the Device feature is a runtime failure the exam expects you to trace back to the manifest, not the TypeScript.
Device and Utility in Practice
context.device turns a code component into a mobile-capable input surface directly inside a form — a rating component might call context.device.captureImage() to attach a photo, or a field-service scenario might call getCurrentPosition() to stamp a record with GPS coordinates, all from inside the same component that also renders the field's value. context.utility.lookupObjects() opens the platform's own standard lookup dialog rather than requiring the developer to build a custom picker UI, and getEntityMetadata() lets a component adapt its behavior to a table's actual schema (for example, respecting a column's precision or option-set choices) instead of hardcoding assumptions.
Dataset Paging and the Factory
For dataset-type components, the bound dataset — reached at context.parameters.<datasetName> — exposes its own paging surface, distinct from context.factory. Loading additional rows of a large subgrid uses the dataset's paging object (for example, loadNextPage()), while context.factory.requestRender() is the general mechanism for telling the platform "re-invoke updateView() now" when an asynchronous operation completes and the component's rendered output needs to catch up with new state.
Implementing Interfaces for React-Based Components
Components built with React implement ComponentFramework.ReactControl<IInputs, IOutputs> instead of the standard DOM-manipulation interface. In this model, updateView() returns a React element rather than manipulating container directly, and the platform reconciles that element using its own bundled React instance. A component must reference React as a platform-library resource in the manifest rather than bundling its own copy — shipping a second, conflicting React instance inside the component's bundle is a well-known source of runtime errors and unnecessarily large bundle sizes, and is a pattern PL-400 expects you to recognize as incorrect.
Pushing Output Back to the Form
Whatever interface style a component uses, the output-binding pattern is the same: internal state changes call notifyOutputChanged(), which signals the platform that new output values are ready. The platform responds by calling getOutputs() to retrieve them and, for field components, marks the bound attribute dirty so the change participates in the form's next save — closing the loop between a component's internal logic and the Dataverse record it's ultimately bound to.
Respecting Security Metadata
context.parameters doesn't just carry a value — for a bound field, it also carries security metadata reflecting the current user's field-level security and the record's state: security.readable, security.editable, and similar flags. A well-built component checks these before rendering an editable control, rather than assuming every user who can see the field can also change it; ignoring security.editable and rendering an always-editable input would let a component silently bypass field-level security that the platform is otherwise enforcing everywhere else on the form. This mirrors the same client-side-versus-platform-security distinction introduced earlier in this chapter for standard form controls, and PCF components are held to the same standard because they are, from Dataverse's perspective, just another way of rendering a secured field.
Formatting and Parsing Helpers
context.formatting complements context.utility with locale-aware helpers — formatting a Date or currency value according to the current user's language and regional settings, and parsing user-entered text back into a typed value the component can pass to notifyOutputChanged(). Relying on these helpers instead of hand-rolled string formatting keeps a component's display consistent with every other control on the form, across the full range of languages and locales an organization's users might be running, without the component author having to reimplement locale logic themselves.
A dataset-type PCF component needs to load the next page of a large subgrid's records. Which object exposes that paging capability?
Which context sub-API should a component call to scan a barcode using the device camera as part of its logic?