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 build Choice Relay 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 Sync to Teams action to synchronize the agent to the tenant catalog. Synchronizing is not the same as installing: the agent then has to be installed from the Agents page in the Microsoft 365 admin center at admin.cloud.microsoft/#/agents/all
. That step is easy to miss, because the app appears as published in the Teams admin center well before it is usable. Once it is installed, 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: from a prompt to a choice and back
In the next post, I build Choice Relay, a deliberately small two-tool app that makes the hand-off easy to follow:
- the user describes a situation and asks for a few sensible actions;
- Copilot may select
ChoiceRelayShowChoicesand supply the question and options as structured arguments; - the user selects one option in the SPFx component;
- the component sends that selection back as a readable user turn through the preview bridge;
- Copilot may select
ChoiceRelayShowNextActionand render one suggested next action with an explanation; and - the user can ask for an adjustment from inside the component, or from the normal Copilot chat.
The tools are generic and carry no business scenario. The selected tool, generated arguments, outbound message, and host acknowledgement remain available in a collapsed Under the hood view, while the main UI stays focused on the choice itself.