mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
ea3e3fbfa6
Fixes #261 (open since March 2024). Supersedes #4622 — @ashish4143 diagnosed the same wrappers and is credited as co-author on the commit. ## The bug `CopilotSidebar` wraps consumer content in two divs: - `.copilotKitSidebarContentWrapper` (`Sidebar.tsx`) — only sets `overflow`, `margin-right`, `transition` - `.copilotKitModalChildrenWrapper` (`Modal.tsx`) — **has no CSS rule anywhere in the repo** Both are auto-height blocks, so a child's `height: 100%` has no definite containing block to resolve against and collapses to content height. ## The fix An opt-in `fullHeightChildren` prop on `CopilotSidebar` that adds a modifier class to the content wrapper. Two deliberate choices, both from the review on #4622: - **Opt-in, not default.** The content wrapper wraps the *entire* consumer app. Making it a fixed-height flex column for everyone would reflow apps that never asked for it. - **A viewport unit, not `height: 100%`.** `100%` only resolves if every ancestor (`html`/`body`/`#root`) also declares a height — react-ui neither sets that nor can guarantee it, so `100%` would silently no-op in a stock Next.js app. `min-height: 0` on the children wrapper clears the flex-item `min-height: auto` floor so tall content scrolls inside the child rather than stretching the wrapper past the viewport. ```tsx <CopilotSidebar fullHeightChildren> <div style={{ height: "100%" }}>...</div> </CopilotSidebar> ``` ## Testing **Unit** — `packages/react-ui/src/css/sidebar-full-height.test.ts` (4 tests), in the repo's existing CSS-contract style. Guards both halves: the escape hatch's rules, and that the default wrapper stays auto-height. Also asserts the height is *not* `100%`, since that's the regression that would make the whole feature a silent no-op. ``` ✓ src/css/sidebar-full-height.test.ts (4 tests) Test Files 9 passed (9) Tests 58 passed (58) # full react-ui suite ``` `npx tsc --noEmit` → exit 0. `oxlint` on changed files → 0 warnings, 0 errors. **Live in Chrome** — the acceptance criterion from the #4622 review: a stock app where **nothing** declares a height on `html`/`body`/`#root`, loading the real built `dist/index.css` (not the source CSS), standards mode, 762px viewport. DOM per `Sidebar.tsx:92` + `Modal.tsx:143`. | case | child `height:100%` measures | |---|---| | default (no opt-in) | **17px** — collapsed, i.e. behavior unchanged for existing consumers | | `fullHeightChildren` | **762px** — exactly the viewport | | `fullHeightChildren`, content 3000px tall | **762px**, scrolls inside the child (`min-height: 0` holds) | Also confirmed on the opt-in path: `.copilotKitSidebar` stays `position: fixed`, and the expanded push-aside `margin-right` is still `448px` (28rem), so the sidebar's own layout is untouched. **Docs** — `CopilotSidebar.mdx` is auto-generated from `Sidebar.tsx`; regenerated via `scripts/docs/gen.ts` and committed only the new `fullHeightChildren` entry (the generator also surfaces unrelated pre-existing drift in other reference pages, left out of this PR). ## Not covered The issue mentions a "works in Safari, not Chrome" symptom. I verified in Chromium only — the mechanism above is spec behavior rather than a Chrome quirk, but I haven't measured WebKit.
CopilotKit - React UI
✨ Why CopilotKit?
- Minutes to integrate - Get started quickly with our CLI
- Framework agnostic - Works with React, Next.js, AGUI and more
- Production-ready UI - Use customizable components or build with headless UI
- Built-in security - Prompt injection protection
- Open source - Full transparency and community-driven
🧑💻 Real life use cases
Deploy deeply-integrated AI assistants & agents that work alongside your users inside your applications.
🖥️ Code Samples
Drop in these building blocks and tailor them to your needs.
Build with Headless APIs and Pre-Built Components
// Headless UI with full control
const { visibleMessages, appendMessage, setMessages, ... } = useCopilotChat();
// Pre-built components with deep customization options (CSS + pass custom sub-components)
<CopilotPopup
instructions={"You are assisting the user as best as you can. Answer in the best way possible given the data you have."}
labels={{ title: "Popup Assistant", initial: "Need any help?" }}
/>
// Frontend actions + generative UI, with full streaming support
useCopilotAction({
name: "appendToSpreadsheet",
description: "Append rows to the current spreadsheet",
parameters: [
{ name: "rows", type: "object[]", attributes: [{ name: "cells", type: "object[]", attributes: [{ name: "value", type: "string" }] }] }
],
render: ({ status, args }) => <Spreadsheet data={canonicalSpreadsheetData(args.rows)} />,
handler: ({ rows }) => setSpreadsheet({ ...spreadsheet, rows: [...spreadsheet.rows, ...canonicalSpreadsheetData(rows)] }),
});
Integrate In-App CoAgents with LangGraph
// Share state between app and agent
const { agentState } = useCoAgent({
name: "basic_agent",
initialState: { input: "NYC" }
});
// agentic generative UI
useCoAgentStateRender({
name: "basic_agent",
render: ({ state }) => <WeatherDisplay {...state.final_response} />,
});
// Human in the Loop (Approval)
useCopilotAction({
name: "email_tool",
parameters: [
{
name: "email_draft",
type: "string",
description: "The email content",
required: true,
},
],
renderAndWaitForResponse: ({ args, status, respond }) => {
return (
<EmailConfirmation
emailContent={args.email_draft || ""}
isExecuting={status === "executing"}
onCancel={() => respond?.({ approved: false })}
onSend={() =>
respond?.({
approved: true,
metadata: { sentAt: new Date().toISOString() },
})
}
/>
);
},
});
// intermediate agent state streaming (supports both LangGraph.js + LangGraph python)
const modifiedConfig = copilotKitCustomizeConfig(config, {
emitIntermediateState: [
{
stateKey: "outline",
tool: "set_outline",
toolArgument: "outline",
},
],
});
const response = await ChatOpenAI({ model: "gpt-4o" }).invoke(
messages,
modifiedConfig,
);
🏆 Featured Examples
Documentation
To get started with CopilotKit, please check out the documentation.