AgentStack
SKILL verified MIT Self-run

Pcf

skill-korchard333-claude-power-platform-community-pcf · by korchard333

PCF (Power Apps Component Framework) control development. Use when: building PCF controls, ReactControl, dataset controls, manifest patterns, Fluent UI v9 integration, Canvas App deployment, debugging PCF.

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-korchard333-claude-power-platform-community-pcf

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Pcf? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Skill: PCF (Power Apps Component Framework)

When to Use

Trigger when building, debugging, or reviewing PCF controls — TypeScript React components for Model-Driven or Canvas Apps.


Project Structure

MyControl/
├── MyControl/
│   ├── index.ts              # Main control class (StandardControl or ReactControl)
│   ├── MyComponent.tsx       # React component
│   ├── css/styles.css        # Component styles
│   ├── strings/              # Resx localization files
│   └── generated/
│       └── ManifestTypes.d.ts  # Auto-generated from manifest
├── ControlManifest.Input.xml # Component manifest (properties, resources)
├── MyControl.pcfproj         # Project file
├── package.json
├── tsconfig.json
└── solutions/
    └── Solution.cdsproj      # Solution project for deployment

Control Types

ReactControl (Virtual — Recommended for New Development)

// No DOM container — React manages rendering
export class MyControl implements ComponentFramework.ReactControl {
  private notifyOutputChanged: () => void;

  public init(context: ComponentFramework.Context, notifyOutputChanged: () => void): void {
    this.notifyOutputChanged = notifyOutputChanged;
  }

  public updateView(context: ComponentFramework.Context): React.ReactElement {
    return React.createElement(MyComponent, {
      value: context.parameters.sampleProperty.raw ?? "",
      disabled: context.mode.isControlDisabled,
      onChange: (val: string) => {
        this._value = val;
        this.notifyOutputChanged();
      },
    });
  }

  public getOutputs(): IOutputs {
    return { sampleProperty: this._value };
  }

  public destroy(): void { /* cleanup */ }
  private _value: string = "";
}

StandardControl (Legacy — Has DOM Container)

// Gets a container div for direct DOM manipulation
export class MyControl implements ComponentFramework.StandardControl {
  private container: HTMLDivElement;

  public init(context, notifyOutputChanged, state, container: HTMLDivElement): void {
    this.container = container;
  }

  public updateView(context): void {
    ReactDOM.render(React.createElement(MyComponent, props), this.container);
  }

  public destroy(): void {
    ReactDOM.unmountComponentAtNode(this.container);
  }
}

Manifest Patterns

Field Control

> ⚠️ CRITICAL: Virtual controls using React/Fluent MUST declare `` elements. Without these, the PCF bundles its own React — and the platform ALSO provides React — resulting in two React instances. Fluent UI v9 hooks immediately fail with "Invalid hook call… more than one copy of React" and bundle size bloats from ~16 KB to ~2.5 MB.


  
  
    
    
    
    
    
  

With platform-library declarations:

  • Move @fluentui/react-components, react, and react-dom to devDependencies (types only at compile time)
  • bundle.js drops from ~2.5 MB → ~16 KB
  • The platform provides one shared React instance to all virtual controls on the page

Official docs: platform-library element reference — this is Category B, fully documented.

Dataset Control


  
  

Dataset Paging Pattern

public updateView(context: ComponentFramework.Context): React.ReactElement {
  const dataset = context.parameters.dataSetGrid;

  if (dataset.loading) return React.createElement("div", null, "Loading...");

  const records = dataset.sortedRecordIds.map((id) => {
    const record = dataset.records[id];
    return {
      id,
      name: record.getFormattedValue("name"),
      status: record.getFormattedValue("statuscode"),
    };
  });

  const hasMore = dataset.paging.hasNextPage;
  const loadMore = () => dataset.paging.loadNextPage();

  return React.createElement(MyGrid, { records, hasMore, loadMore });
}

Fluent UI v9 Integration

// PERFORMANCE: Import guidance for Fluent UI v9
// The barrel import tree-shakes correctly with modern bundlers (webpack 5+, esbuild):
import { Button, Input, Label } from "@fluentui/react-components"; // OK with tree-shaking

// For smaller bundles, use individual package imports:
import { Button } from "@fluentui/react-button";
import { Input } from "@fluentui/react-input";
// Check package availability — not all components have separate packages

// Wrap in FluentProvider for consistent theming
public updateView(context): React.ReactElement {
  return React.createElement(
    FluentProvider,
    { theme: webLightTheme },
    React.createElement(MyComponent, props)
  );
}

React Platform Library Versions

> Last verified: March 2026. Check Microsoft Learn for current versions.

> IMPORTANT: The PCF platform library does NOT use React 18. The actual versions are:

| Context | React Version | Notes | |---|---|---| | Build (bundled) | 16.14.0 | Version used at compile time | | Model-Driven App runtime | 17.0.2 | Provided by the MDA shell at runtime | | Canvas App runtime | 16.14.0 | Provided by the Canvas runtime |

Do NOT use React 18-specific APIs such as useTransition, useDeferredValue, useSyncExternalStore, or concurrent rendering features — they are not available in the platform library.

Fluent UI v9 Version Constraints

| Context | Fluent UI v9 Version | |---|---| | Build (max) | ≤ 9.46.2 | | Runtime (provided) | 9.68.0 |

Do not install Fluent UI v9 packages above 9.46.2 in your project — the build will succeed but runtime mismatches may cause unexpected behavior.

ReactControl (Virtual — Recommended)

ReactControl (virtual, control-type="virtual") uses the platform-provided React automatically — no manual createRoot needed. The control-type="virtual" attribute is required for React controls. This is the recommended approach for all new controls.

StandardControl (Legacy — Has DOM Container)

For StandardControl using React, use ReactDOM.render / ReactDOM.unmountComponentAtNode (matching the React 16/17 API):

import * as ReactDOM from "react-dom";

export class MyControl implements ComponentFramework.StandardControl {
  private container: HTMLDivElement;

  public init(context, notifyOutputChanged, state, container: HTMLDivElement): void {
    this.container = container;
  }

  public updateView(context): void {
    ReactDOM.render(React.createElement(MyComponent, props), this.container);
  }

  public destroy(): void {
    ReactDOM.unmountComponentAtNode(this.container);
  }
}

Recommendation: Always prefer ReactControl (virtual) — it handles React lifecycle correctly and avoids DOM container issues.

Platform Support Limitations

  • PCF controls are NOT supported in Power Pages — only Model-Driven Apps and Canvas Apps
  • When using platform libraries, do not bundle React or Fluent UI as externals — this causes double-loading

ESLint Setup for PCF

pac pcf push runs npm install internally. Extra ESLint devDependencies cause ERESOLVE failures due to incompatible peer requirements.

Use minimal ESLint only:

// package.json — devDependencies
"eslint": "^9.0.0"
// DO NOT add: typescript-eslint, eslint-plugin-promise, @typescript-eslint/eslint-plugin, eslint-plugin-react
// These have incompatible peer requirements that cause pac pcf push to fail
// eslint.config.mjs — minimal config that satisfies pcf-scripts peer dep
export default [
  { ignores: ["node_modules/**", "out/**", "obj/**", "generated/**"] }
];

No TypeScript-ESLint, no eslint-plugin-react, no globals package needed. pcf-scripts only needs ESLint as a peer dep.

scheduler Dependency

@fluentui/react-context-selector imports scheduler directly. npm may install it nested inside react-dom/node_modules/ rather than hoisted to the project root. If webpack reports "Module not found: Can't resolve 'scheduler'", add it explicitly:

"scheduler": "^0.20.2"

Must be ^0.20.2@fluentui/react-components@9.46.2 requires ^0.19.0 || ^0.20.0; version 0.27.x causes peer conflict during pac pcf push.


CLI Workflow

# Create new control
pac pcf init --namespace Contoso --name MyControl --template field --framework react

# Install dependencies
npm install

# Local development with test harness
npm start watch    # Opens http://localhost:8181

# Build
npm run build

# Create solution project
pac solution init --publisher-name Contoso --publisher-prefix contoso
pac solution add-reference --path ../MyControl

# Build solution
dotnet build    # or msbuild /t:build /restore

# Push to environment (dev only)
pac pcf push --publisher-prefix contoso

Best Practices

  • Always implement destroy() — clean up event listeners, timers, subscriptions
  • Always handle context.mode.isControlDisabled — disable inputs when form is read-only
  • Always handle context.mode.isVisible — skip rendering when hidden
  • Diff props in updateView before re-rendering to avoid flicker
  • Use control-type="virtual" for React controls (required for platform library React)
  • Never call notifyOutputChanged() inside updateView() — causes infinite loops
  • Use context.webAPI for Dataverse operations (respects user security context)
  • Use context.navigation for dialog/form opening
  • Always specify required-feature-set in manifest when using WebAPI

Debugging

  1. Test Harness: npm start watchhttp://localhost:8181
  2. In Environment: Browser DevTools → Sources → webpack:// → find your .tsx files
  3. Fiddler/DevTools Network: Capture api/data/v9.2 calls for dataset debugging
  4. Check context.parameters.xxx.errorMessage for binding errors
  5. Check context.parameters.xxx.security for field-level security restrictions

Canvas App Deployment

PCF controls can be used in Canvas Apps, but require additional manifest configuration.

Enable for Canvas Apps


  

  
  
    
    
  

  
    
  

Canvas App vs Model-Driven App Differences

| Feature | Model-Driven App | Canvas App | |---|---|---| | context.webAPI | Available | Available (if declared in feature-usage) | | context.navigation | Full support | Limited (no openForm) | | context.mode.isControlDisabled | Managed by form | Managed by app maker | | Dataset controls | Full support | Supported (with limitations) | | Theming | Inherits MDA theme | Inherits Canvas theme | | notifyOutputChanged() | Triggers form dirty | Triggers OnChange in Canvas |

Import to Canvas App

Canvas App → Insert → Get more components → Code tab → Import → Select your PCF control

Anti-Patterns

  • Calling notifyOutputChanged() in updateView() (infinite render loop)
  • Not implementing destroy() (memory leaks, stale listeners)
  • Ignoring isControlDisabled (control remains editable on read-only forms)
  • Using any types for context parameters
  • Hardcoding entity names or field names (use manifest properties)
  • Not handling loading state for dataset controls
  • Using React 18-specific APIs (useTransition, useDeferredValue, concurrent features) — platform provides React 16.14.0/17.0.2
  • **Missing ` declarations** in virtual control manifest — causes two React instances, "Invalid hook call" error, and ~2.5 MB bundle instead of ~16 KB. Always declare both React and Fluent` platform libraries for virtual controls using Fluent UI v9.

Sub-Files

  • [PCF API Reference](api-reference.md) — Context object properties, context.mode, context.webAPI methods, context.navigation, context.device, context.formatting, DataSet API (columns/filtering/paging/records), EntityRecord methods, custom events, platform availability matrix (MDA vs Canvas vs Portals)

Related Skills

  • code-apps — React/TypeScript patterns shared with PCF development
  • accessibility-ux — WCAG compliance requirements for PCF controls

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.