Primitives
Headless building blocks for teams that want to build their own support UI.
This page is for the full-custom path. If you want the ready-made widget, stay in <Support />. If you want to build your own support UI, these primitives are the building blocks underneath it.
For a complete implementation, use the support source as your base and pull in only the primitives you need.
Primitives are headless UI pieces. Inside the widget runtime they can read provider state, but outside that runtime you should pass explicit state, handlers, and data.
Use this page when
Supportandslotsare no longer enough- you want to own the support shell, layout, and interaction model
- you want reusable building blocks instead of copying a monolithic widget
Import
Use named imports from the focused primitives entry. This lets bundlers remove timeline, feedback, markdown, and input code you do not render.
import { Trigger, Window } from "@cossistant/react/primitives";The Primitives namespace on the root package remains compatible, but it can
retain a much larger primitive graph when the namespace is observed at runtime.
Smallest working example
import { Trigger } from "@cossistant/react/primitives";
import { useState } from "react";
function CustomWidget() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Trigger
isOpen={isOpen}
isTyping={false}
onToggleOpen={() => setIsOpen((value) => !value)}
unreadCount={0}
>
{({ isOpen }) => (
<span>{isOpen ? "Close support" : "Open support"}</span>
)}
</Trigger>
{isOpen ? (
<div className="fixed bottom-20 right-4 w-96 border bg-white shadow-xl">
<button onClick={() => setIsOpen(false)} type="button">
Close
</button>
<p>Custom support content</p>
</div>
) : null}
</>
);
}Trigger is provider-free when you pass isOpen, onToggleOpen,
unreadCount, and optional isTyping. Window is designed for the
widget runtime and should stay inside SupportProvider or Support.Root.
import { Window } from "@cossistant/react/primitives";
import { useSupportConfig } from "@cossistant/react/support-config";
function RuntimeWindow() {
const { isOpen } = useSupportConfig();
return (
<Window>
{({ close }) =>
isOpen ? (
<div className="fixed bottom-20 right-4 w-96 border bg-white shadow-xl">
<button onClick={close} type="button">
Close
</button>
<p>Custom support content</p>
</div>
) : null
}
</Window>
);
}Common building blocks
This is a selected starting set, not a complete export catalog. Inspect the
@cossistant/react/primitives type declarations for the version you install.
Shell and routing
Primitives.TriggerPrimitives.WindowPrimitives.RouterPrimitives.Config
Conversation UI
Primitives.ConversationTimelinePrimitives.TimelineItemPrimitives.TimelineItemGroupPrimitives.ToolActivityRow
Input and feedback
Primitives.MultimodalInputPrimitives.FileInputPrimitives.FeedbackCommentInputPrimitives.FeedbackRatingSelectorPrimitives.FeedbackTopicSelect
Shared display pieces
Primitives.AvatarPrimitives.DaySeparatorPrimitives.TypingIndicatorPrimitives.Button
Accessibility responsibilities
Headless means you own the user experience. A production shell must provide:
- a trigger with an accessible name and a target of at least 44 by 44 CSS pixels
- dialog or complementary-region semantics appropriate to the layout
- initial focus, a contained keyboard path, Escape handling, and focus return
- visible focus states, labels and errors for every input, and announced status changes
- responsive sizing, zoom support, and reduced-motion behavior
The smallest example demonstrates state and focused imports only. Use the shipped Support source as the reference for these interaction details.
When to stop here
- the headless build is working and you only need hooks or shared types next
- you still want Cossistant state, navigation, and message APIs under your own UI
Next step
- Advanced for the full-custom path and source-code starting point
- Hooks Reference for state, visitor, and navigation control
- Types Reference for the shared data models behind the primitives
Was this page helpful?
Open a prefilled documentation issue so the team can act on your feedback.