FabrCore ChatDock component — floating icon chat panel overlay for Blazor Server, all parameters, positions, scoped ChatDock, multiple ChatDocks with ChatDockManager, agent lifecycle, and customization. Triggers on: "ChatDock", "ChatDockPosition", "ChatDockManager", "chat panel", "floating chat", "chat overlay", "chat icon", "chat UI component", "ChatDock position", "multiple ChatDocks", "LazyLoad chat", "OnMessageReceived", "OnMessageSent", "chat dock", "BottomRight", "BottomLeft", "chat component", "fabrcore.css". Do NOT use for: client setup (AddFabrCoreClient, ClientContext) — use fabrcore-client. Do NOT use for: agent development — use fabrcore-agent.
The ChatDock is a floating icon button that expands into a chat panel overlay. When collapsed, it shows a small circular icon (36x36px). When clicked, a chat panel slides in from the configured position. The panel is moved to document.body via JS to escape CSS stacking contexts.
@using FabrCore.Client.Components
<ChatDock UserHandle="user1"
AgentHandle="assistant"
AgentType="my-agent"
SystemPrompt="You are a helpful assistant."
Title="Assistant" />
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
UserHandle | string | Yes | — | User/client identifier |
AgentHandle |
string |
| Yes |
| — |
| Agent instance handle (unique per agent) |
AgentType | string | Yes | — | Agent type matching [AgentAlias] |
SystemPrompt | string | No | "You are a helpful AI assistant." | System instructions |
Title | string | No | "Assistant" | Display title in panel header |
Icon | string | No | "bi bi-chat-dots" | Bootstrap icon class for the floating button |
WelcomeMessage | string | No | "How can I help you today?" | Empty state message |
Tooltip | string | No | "Open chat" | Hover tooltip on icon |
Position | ChatDockPosition | No | BottomRight | Panel position (see below) |
AdditionalArgs | Dictionary<string,string> | No | null | Extra args for AgentConfiguration |
LazyLoad | bool | No | false | Defer agent creation until first expand |
Plugins | List<string> | No | null | Plugin aliases to enable |
Tools | List<string> | No | null | Standalone tool aliases to enable |
OnMessageReceived | Func<AgentMessage, Task<bool>> | No | null | Callback when agent responds. Return true to display, false to suppress. |
OnMessageSent | EventCallback<string> | No | — | Callback when user sends a message |
public enum ChatDockPosition
{
BottomRight, // Floating icon bottom-right, panel slides up (default)
BottomLeft, // Floating icon bottom-left, panel slides up
Right, // Floating icon right edge, panel slides in from right (full height)
Left // Floating icon left edge, panel slides in from left (full height)
}
Responsive: On mobile (<480px), the panel expands to full width regardless of position.
Scope an agent to a specific context by embedding IDs in the handle and system prompt:
<ChatDock UserHandle="user1"
AgentHandle="@($"project-{ProjectId}")"
AgentType="project-agent"
SystemPrompt="@($"You manage project {ProjectId}. Use this ID automatically.")"
Title="Project Assistant"
OnMessageSent="@(async (msg) => { await RefreshData(); StateHasChanged(); })"
Position="ChatDockPosition.Right" />
Use ChatDockManager (registered via AddFabrCoreClientComponents()) to coordinate multiple instances — only one can be expanded at a time:
<CascadingValue Value="chatDockManager">
<ChatDock UserHandle="user1" AgentHandle="coding-agent"
AgentType="code-reviewer" Title="Code Review"
Position="ChatDockPosition.BottomRight" />
<ChatDock UserHandle="user1" AgentHandle="writing-agent"
AgentType="writer" Title="Writing Help"
Position="ChatDockPosition.BottomLeft" />
</CascadingValue>
@code {
[Inject] ChatDockManager chatDockManager { get; set; } = default!;
}
ChatDock manages the full agent lifecycle internally:
IClientContext via IClientContextFactory, subscribes to AgentMessageReceivedIsAgentTracked() then GetAgentHealth() to check if already configured. For cross-owner agents (handle contains :), goes straight to GetAgentHealth — the agent won't be in the user's tracked list.context.CreateAgent(agentConfig) if IsConfigured == false and the agent is owned by the current user (bare alias handle). Cross-owner agents must be created server-side.context.SendMessage() (fire-and-forget). Responses arrive via AgentMessageReceived.FromHandle (must match expected agent) and ToHandle (must be UserHandle). System messages (_status, _error) handled internally.IDisposable — unregisters from DockManager, unsubscribes events, disposes context.<ChatDock UserHandle="@userId"
AgentHandle="system:automation_agent-123"
AgentType="automation-agent" />
When AgentHandle contains a colon:
FromHandleClientGrain verifies Message permissionLazyLoad="true")document.body via JS to avoid stacking context issues--chat-dock-primary: #3b82f6;
--chat-dock-width: 380px;
--chat-dock-icon-size: 36px;
ChatDock requires FabrCore.Client static assets:
<!-- In App.razor or _Host.cshtml -->
<link href="_content/FabrCore.Client/fabrcore.css" rel="stylesheet" />
The JS module (fabrcore.js) is loaded dynamically by the component.