Every component
Where each exported component is documented, and the ones that have no page of their own.
The four pages in this section cover the components you assemble a product out of. This page is the index — and the home of the handful that belong to no group.
Where each one is covered
| Group | Components | Page |
|---|---|---|
| Shell and navigation | ConnectAppShell, ConnectSidebar*, ConnectSidebarNav, ConnectNav, ConnectUserButton, ConnectProfileModal, ConnectLogo, ConnectMark | Shell |
| Gates | ConnectAccessGate, ConnectFeatureGate, ConnectReadinessGate, ConnectSubscriptionGate, ConnectPlatformGate, ConnectWorkspaceTypeGate | Gates |
| Screens and widgets | ConnectPageShell, ConnectSection, ConnectEmptyState, ConnectSettingRow, ConnectStatusChip, ConnectFilterTabs, ConnectUsageMeter, ConnectSeatUsage, ConnectTrialBanner, ConnectGrievanceNotice | Screens |
| Workspaces | ConnectWorkspaceSwitcher, ConnectAppsGrid | Workspaces |
| Plans and billing | ConnectPlans, ConnectPlansPage, ConnectSubscribeDialog, ConnectSubscriptionCard, ConnectReadinessBanner | Screens |
| Sign-in | ConnectLoginButton, ConnectRegisterButton, ConnectSignOutButton, ConnectOneTap | Authentication |
| Assistants | ConnectAskAi | AI |
ConnectVisitorChat | Visitor assistant | |
ConnectLinkButton | Below, on this page |
Props for all of them are in the generated client reference; the six presentational ones that render in a Server Component are in UI.
The ones with no group
ConnectLinkButton
The only supported way to render a link that looks like a button. HeroUI v3's
Button has no as prop, so <Button as={Link}> neither type-checks nor
works — this goes through HeroUI's render instead:
import Link from "next/link";
import { ConnectLinkButton } from "@cosmoops/connect-sdk/client";
<ConnectLinkButton href="/deals" renderLink={(props) => <Link {...props} />}>
Open board
</ConnectLinkButton>Pass renderLink whenever your router has one. Without it this falls back
to a plain <a href>, which navigates under any router but costs a full
document load — in an App Router app that throws away the client cache and
re-runs the whole tree, very visible on a button sitting inside a page the
user is already working in. Same shape as AppShell's own renderLink, so a
host declares its router once and hands the same function to both.
ConnectConfirmDialog
The confirmation in front of a destructive action.
It closes on confirm, not on response. Holding the modal open until the server answers makes every delete feel like a form submission, and the error path already has somewhere to go — a toast, or the row reappearing. A dialog that stays open to report failure is right only where the failure is expected and correctable in place (a seat cap, a last-admin invariant), and that is a blocking form, not this.
onConfirm may return a promise. It is not awaited before closing, but a
rejection is caught rather than escaping — an error thrown out of an async
transition reaches the nearest error boundary and takes the page down.
The trigger is a direct child
Pass your button as a direct child, never wrapped in Modal.Trigger. That
wrapping renders a div role="button" inside React Aria's Pressable and
relies on a plain onClick bubbling up; a React Aria button nested inside
calls stopPropagation() in its own press handler, so the click never
arrives and the dialog silently never opens.
ConnectCursorPagination
Next / previous for a cursor-paginated list. There is no "page 7 of 42" because a keyset-paginated list cannot know how many pages there are without a second count query over the same filter — a billed index scan for a number nobody acts on. What a user does act on is more and back, and those are exact.
The row count is announced in a live region, so a screen-reader user learns that filtering or paging changed the result set. Without it the table silently swaps its contents.
ConnectNoSubscriptionCard
The "you are not on a plan yet" card. It points at your own /plans page
rather than opening Connect: choosing a plan is browsing, it belongs in your
product where your pricing story is, and only the final confirmation needs to
happen on Connect. plansHref is overridable, because not every app mounts its
catalogue at /plans.
Rendered on its own it is just a card. ConnectSubscriptionGate is the usual
way in, since it picks this only when there is genuinely nothing to show.
ConnectAccountSessions
Every device signed into this Connect account — not scoped to your application, because a Connect session is one browser's login to Connect itself and can back sign-ins to every application the user has authorized from it. Current device first, then most recently active.
It owns the one useConnectSessions() call for the modal it sits in, and each
revoke re-reads the list itself; nothing invalidates it automatically.
ConnectIntegrationsModal
A grid of every Composio-hosted toolkit the workspace can connect — Google Calendar, Slack, and whatever else a platform admin enabled in Connect's Console. Each tile carries its own connect / reconnect / disconnect action and its own pending state, independent of the others.
Not optimistic, deliberately: a tile stays as it was after Connect is
pressed, because the connection is not settled until Composio's webhook
confirms it — and the browser has navigated away to the provider's OAuth
screen by then anyway. Renders nothing when signed out, same as
ConnectAppsGrid.
ConnectBookingCalendar, ConnectBookingDialog, ConnectBookingDetail
The scheduling trio, over a subscribing workspace's own diary.
ConnectBookingDialog— picking a time, then who it is for. The slot list is read fresh on every open and never cached across one: it is a snapshot of contention, and offering a time somebody took ninety seconds ago is how two people end up in the same slot. The server re-checks inside its transaction regardless, so a stale list costs a refusal rather than a double booking — this only makes the refusal rare enough to be surprising.ConnectBookingDetail— one appointment, and the two things anyone opens it to do. Rescheduling re-reads the slots withexcludeBookingIdset to this booking; without that the appointment blocks its own replacement, and moving it by half an hour — the only move most people ever make — offers nothing.
Hooks
Every component above has a hook underneath it, and the hook is the escape
hatch when you want the data without the markup: useConnect,
useConnectUser, useConnectEntitlements, useConnectFeature,
useConnectPlans, useConnectCheckout, useConnectAddonUsage,
useConnectApps, useConnectWorkspaces, useConnectWorkspaceMembers,
useConnectWorkspaceType, useConnectSessions, useConnectIntegrations,
useConnectPush, useConnectPlatformAccess, useConnectCompanyProfile,
useConnectAudience, useBookableEventTypes, useAvailableSlots,
useBookings, useBookingActions, useActivePath, useConnectResource,
useConnectOptional, useConnectShell, useConnectAccessGate.
Signatures and return types are in the client reference. Two worth knowing about by name:
useConnectResourceis the generic one the others are built on — one bridge read, shared through the provider's cache. It waits for a session by default, since every resource route but one needs it and firing early buys a guaranteed 401;requiresSession: falseopts out, which is what the grievance notice on a public page needs.useConnectOptionalinherits the context when there is one and does not throw when there is not — for a component whose whole purpose is the visitor who has no session. It is not a way to make an ordinary component tolerant of a missing provider: a session-reading component that silently renders a signed-out state because somebody forgot to wrap their app is a bug that looks like a product decision.