Skip to main content

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

  • Support and slots are 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.Trigger
  • Primitives.Window
  • Primitives.Router
  • Primitives.Config

Conversation UI

  • Primitives.ConversationTimeline
  • Primitives.TimelineItem
  • Primitives.TimelineItemGroup
  • Primitives.ToolActivityRow

Input and feedback

  • Primitives.MultimodalInput
  • Primitives.FileInput
  • Primitives.FeedbackCommentInput
  • Primitives.FeedbackRatingSelector
  • Primitives.FeedbackTopicSelect

Shared display pieces

  • Primitives.Avatar
  • Primitives.DaySeparator
  • Primitives.TypingIndicator
  • Primitives.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.