SPFx was a visionary step for SharePoint extensibility. It has since become the most widely used extensibility model in Microsoft 365. Microsoft says solutions built with it already serve tens of millions of people every day, backed by years of production use, a large community, and the JavaScript ecosystem.
On 9 July 2026, Microsoft opened another chapter. SharePoint Copilot Apps, now in public preview with SPFx 1.24, let an SPFx component render directly inside Microsoft 365 Copilot. It is still built, packaged, and deployed as SPFx. The user simply reaches it in a completely new way: by describing what they need.
I have now tested this integration end to end, and I am honestly impressed. Copilot can select an SPFx tool, turn the user’s request into structured properties, and render the component in the conversation. The interaction is conversationally bidirectional: the component can add a new user turn to the same conversation, and Copilot can invoke the next SPFx tool.
That is the part that excites me. We can keep the SPFx skills, ecosystem, and deployment model we already know, then add natural-language intent and Copilot orchestration on top. To me, this feels like the next big step in the SPFx story.
Part 1 of the SPFx Copilot Apps series. This post explains the foundations. In Part 2, I will build Hello Copilot Lab and make the complete route visible. Prompt Fortress will then take the same architecture much further, and I already have more implementations in mind.
What actually changed
A Copilot component is a new SPFx component type. It extends BaseCopilotComponent instead of BaseClientSideWebPart, but the surrounding engineering remains familiar: TypeScript, React or another web framework, Heft, the @microsoft/sp-* libraries, and a standard .sppkg deployed through the SharePoint app catalog.
The useful comparison is not “old SPFx versus AI.” It is the same web skills entering a different host:
| Concern | SPFx web part | SPFx Copilot component |
|---|---|---|
| Host | SharePoint page | Microsoft 365 Copilot canvas |
| Trigger | Page load and user interaction | Declarative-agent tool invocation |
| Base class | BaseClientSideWebPart |
BaseCopilotComponent |
| Initial input | Web-part properties and page placement | Tool arguments from propertiesSchema and Copilot host context |
| SharePoint data target | Often the site containing the page | Configure it explicitly when the app depends on a particular site |
| Layout | Page section | inline or fullscreen |
| Package | .sppkg |
One .sppkg containing the agent and Copilot components |
| Fluent UI package added by the React template | v8 (@fluentui/react) |
v9 (@fluentui/react-components) |
That last row surprised me. The standard SPFx React template still adds Fluent UI v8, while the new Copilot React template adds and uses Fluent UI v9. This is a generator choice, not a host restriction: existing v8 code remains valid. Microsoft’s current PnP preview samples follow the same v9 pattern with React 17.
During public preview, end users run these components in Microsoft 365 Copilot. Developers can load and debug them locally in the new Copilot Workbench.
One package, two kinds of code
A SharePoint Copilot App is one SPFx solution. It contains the declarative agent configuration—manifest, instructions, actions, and optional conversation starters—plus one or more Copilot components with their tools and interactive UI. The build packages everything into the same .sppkg.
The component is more than a React component. It is an SPFx component with its own manifest, lifecycle, display modes, and one or more declared tools. React sits inside that host wrapper.
The important project areas are:
copilot/ # agent manifest, instructions, action metadata
config/copilot-agent.json # groups component IDs into the agent
src/copilotComponents/ # BaseCopilotComponent implementations
<component>/
*.manifest.json # tool name, description, display modes
*Properties.ts # Zod -> JSON Schema tool arguments
Part 2 will scaffold every file. For now, the distinction is enough: the agent tells Copilot what the application does, and each tool defines a typed route into a component.
How a prompt reaches the component
Before Copilot can choose one of our tools, the agent has to be active. Deployment makes it discoverable in the tenant agent catalog. The user can then select it from the agent list or target it from a normal Copilot chat with @<agent name>. Typing the agent’s name as ordinary chat text does not activate it.
Once the agent is selected, routing is tool-first. Microsoft 365 Copilot chooses a tool, creates arguments that match that tool’s JSON Schema, and the Microsoft-managed MCP Apps route loads the component that owns it.
Three descriptions shape that decision:
instruction.txtdefines the agent’s behavior and routing rules;- the authored
ai-plugin.jsonadds the action namespace and model-facing summary; and - each component manifest’s tool description and generated JSON Schema define when and how that tool is called.
Conversation starters are useful example prompts. They help a user begin, but they are not themselves the routing target.
- A prompt—or a follow-up typed in the Copilot chat—starts a user turn.
- Copilot reads the agent instructions, tool description, and JSON Schema.
- When the intent matches, Copilot selects the tool and creates its arguments.
- Microsoft-managed MCP Apps routing loads the owning component.
BaseCopilotComponentreceives the properties and renders the SPFx UI.- The component can ask the beta bridge to add another user turn; acknowledgement confirms delivery only.
- Copilot receives that turn and may answer or select a tool again.
The diagram is a loop, not a one-way pipeline. Copilot handles the initial route and remains part of the interaction after SPFx renders. The component can ask the bridge to add another user turn, which Copilot can answer directly or route to another tool.
Using SharePoint data
A Copilot component still runs inside SPFx, so it can use familiar SPFx services such as spHttpClient and the Microsoft Graph client to call Microsoft 365 on behalf of the signed-in user.
There is no SharePoint page behind the Copilot UI. If the app needs data from a particular SharePoint site, configure that site’s URL or ID explicitly and call it through the normal SPFx clients.
Nothing new is required for React state. It has the same rendered-instance lifetime as it does in a web part.
SPFx can continue the Copilot conversation
The public beta bridge is the feature that turns the first render into a continuing interaction:
const result = await this.context.copilotBridge.sendFollowUpMessageAsync([
createCopilotTextContent(message)
]);
if (result.isError) {
// Keep the user's work and offer retry/copy recovery.
}
sendFollowUpMessageAsync asks the host to add a new user turn to the current Copilot conversation. Its result tells us whether the host accepted the message; it does not by itself prove what Copilot did next.
Once the message becomes a new turn, Copilot decides whether to answer directly or select another tool. This is a conversation turn, not a direct callback into the original React instance.
SPFx ^^ Copilot
This is the idea behind the series mark.
Copilot potentiates SPFx. The user describes what they need, Copilot selects a typed tool, and structured arguments shape the component’s first render.
SPFx potentiates Copilot. The component adds the interface, validation, and business interaction that are awkward in chat alone. It can then carry the user’s next action and the current application state into a new Copilot turn.
Together, Copilot brings the user to the right component, and SPFx makes the interaction useful.
MCP Apps underneath
Under the hood, SharePoint Copilot Apps implement the MCP Apps model. With the SPFx path, we do not build or operate an MCP server ourselves: the toolchain generates the action metadata, while Microsoft provides the tenant hosting and routing.
What you can test today
The preview has two different developer loops. Copilot Workbench is the component debugger: select a component, paste its property JSON, then select Fire turn—the Workbench button that passes those properties directly to the component. Copilot is not choosing the tool in that step.
| Test | Copilot Workbench + localhost | Deployed Microsoft 365 Copilot agent |
|---|---|---|
| Component bundle loads | Yes | Yes |
| Supplied JSON properties render | Yes, with Fire turn | Yes, from a tool call |
| Light/dark and inline/fullscreen | Yes | Yes |
| Natural-language tool selection | No—the developer selects the component | Yes |
| Agent instructions | Not exercised | Exercised |
| Component bridge request reaches the host | Yes—host acknowledgement only; there is no model loop | Yes—the new turn enters the conversation |
| Copilot selects a next tool | Not exercised | Yes |
| A follow-up in the normal Copilot chat uses the prior tool context | Not exercised | Yes |
For the fast UI loop, run:
npm start -- --nobrowser
Then open:
https://<tenant>.sharepoint.com/_layouts/15/copilotworkbench.aspx
For intent routing, package the solution, upload it to the app catalog, keep tenant-wide enablement selected, and use the currently labelled Add to Teams action to synchronize the agent to the tenant catalog. Once synchronization completes, open a normal Microsoft 365 Copilot chat, type @<agent name>, select the agent so it appears as a chip in the composer, and send the prompt.
One preview rough edge I encountered is that opening the agent directly did not work in my tenant, while selecting the same agent with @ from a normal Copilot chat did. I shared the workaround in SPFx issue #10946
; Part 2 will show the exact steps.
SharePoint Copilot Apps are in public preview and currently do not require a paid Microsoft 365 Copilot license. Worldwide rollout is expected around 20 July 2026, with automatic agent publishing by the end of July. The 1.24.0-beta.2 toolchain, APIs, host behavior, publishing flow, and licensing may still change before general availability.
Next: build Hello Copilot Lab
In the next post, I will show how I build Hello Copilot Lab, a small two-tool app that makes the complete route visible:
- the user asks for a project update;
- Copilot selects
PuntoBelloComposeUpdateand passes structured fields into an editable SPFx component; - the user asks for a change from inside the component;
- the component sends a versioned follow-up through the beta bridge;
- Copilot selects
PuntoBelloShowReviewand renders the original and revised text side by side; and - the user can also ask for another revision from the normal Copilot chat, where Copilot reuses the preceding tool context.
The UI makes every step visible—the selected tool, structured arguments, follow-up result, turn number, and correlation ID—so you can run it, inspect it, and understand exactly what happens between Copilot and SPFx.