Build your own chat UI with HTML and CSS. cStar binds 60+ data-cstar-* attributes to authentication, messaging, real-time updates, and more.

Build your own chat interface with complete control over HTML, CSS, and behavior. You provide the markup and styling — cStar binds everything automatically via data-cstar-* attributes.

Overview

Custom Mode gives you a lightweight embed (~9KB gzipped) that connects your HTML to cStar's chat backend. Unlike the prebuilt widget, custom mode reads data-cstar-* attributes from your HTML and wires up authentication, messaging, real-time updates, file attachments, and view switching.

cStar switches to custom mode when it sees data-cstar-launcher or data-cstar-panel on the page. No flag, no config.

For programmatic control via npm instead, see @cstar.help/js, @cstar.help/react, and @cstar.help/svelte.

Want a flat reference? All data-cstar-* Attributes is the same content, condensed into Cmd+F-friendly tables.

Installation

<script src="https://www.cstar.help/cstar.js?team=YOUR_TEAM_SLUG"></script>

Replace YOUR_TEAM_SLUG with the value in Settings → Team → Install.

The script scans the page for data-cstar-* attributes and binds them automatically. New attributes added after load are picked up via a MutationObserver — no rebind call needed.

Action Triggers

Add to any clickable element. cStar attaches a click handler.

Attribute What It Does
data-cstar-launcher Toggle the panel open/closed
data-cstar-close Close the panel
data-cstar-minimize Minimize (same as close)
data-cstar-back Return to the conversations list
data-cstar-new-conversation Switch to the new-conversation view
data-cstar-create-conversation Submit the new-conversation form
data-cstar-send Send the current message draft
data-cstar-signup-submit Submit the signup form
data-cstar-login-submit Submit the login form
data-cstar-forgot-password-submit Submit the forgot-password form
data-cstar-magic-link Send a magic link to the email field
data-cstar-logout Log the customer out
data-cstar-switch-to-login Switch the auth view to login
data-cstar-switch-to-signup Switch the auth view to signup
data-cstar-switch-to-forgot Switch the auth view to forgot-password
data-cstar-switch-auth="login|signup" Flexible: switch auth via attribute value
data-cstar-attach-trigger Open the file picker (clicks [data-cstar-attach])
data-cstar-attachment-remove Remove the currently attached file
data-cstar-notifications-enable Request browser push notification permission
data-cstar-notifications-dismiss Dismiss the notification prompt
data-cstar-delete-conversation Delete a conversation. Read data-conversation-id from the element or its closest [data-cstar-conversation] ancestor

Form Inputs

Add to <input>, <textarea>, or <form> elements.

Attribute Element Behavior
data-cstar-input="messageDraft" textarea/input Message composer. Enter sends, Shift+Enter newline. Default if no value given.
data-cstar-input="authEmail" input Email field for auth
data-cstar-input="authName" input Name field for signup
data-cstar-input="authPassword" input Password field for auth
data-cstar-input="subject" input Subject field for new conversations
data-cstar-email input Shorthand for data-cstar-input="authEmail"
data-cstar-name input Shorthand for data-cstar-input="authName"
data-cstar-subject input Shorthand for data-cstar-input="subject"
data-cstar-attach <input type="file"> The hidden file input that data-cstar-attach-trigger clicks
data-cstar-sound-toggle checkbox Toggle agent-message sound notifications
data-cstar-form="signup|login|forgot|compose|prechat|newConversation|new" form Auto-binds the form's submit to the matching SDK action
data-cstar-signup / -login / -compose / -prechat / -newConversation form Boolean alternatives to data-cstar-form

Live Content

cStar updates these elements automatically.

Attribute What It Renders
data-cstar-company-name Your team's company name (textContent)
data-cstar-company-logo Sets src on an <img> to your team logo
data-cstar-status "Online" or "Offline" based on agent presence
data-cstar-unread-count Total unread message count (hidden when 0, "99+" when over 99)
data-cstar-content="currentConversationSubject" Subject of the currently open conversation
data-cstar-connection="connected|connecting|reconnecting|offline" One element per state, shown only when realtime is in that state

View Switching

Define mutually exclusive views. Only the active view is visible.

<div data-cstar-view="auth"><!-- login/signup forms --></div>
<div data-cstar-view="conversations"><!-- conversation list --></div>
<div data-cstar-view="messages"><!-- active conversation --></div>
<div data-cstar-view="new"><!-- new-conversation form --></div>
<div data-cstar-view="offline"><!-- offline fallback --></div>

Combine with auth-form state:

<div data-cstar-view="auth" data-cstar-show-when="authForm:signup"><!-- signup --></div>
<div data-cstar-view="auth" data-cstar-show-when="authForm:login"><!-- login --></div>

Standalone Auth-Form Visibility

If you don't want a separate data-cstar-view="auth" wrapper, hang these on individual auth panels:

Attribute Visible When
data-cstar-auth-signup Auth form is "signup"
data-cstar-auth-login Auth form is "login"
data-cstar-auth-forgot Auth form is "forgot"
data-cstar-forgot-password-sent After forgot-password email is sent

Conditional Visibility (data-cstar-show-when)

Value Visible When
open Panel is open
closed Panel is closed
identified A customer is logged in
anonymous No customer is logged in
online Agents are available
offline No agents available
currentView:conversations|messages|auth|new|offline Current view matches
authForm:signup|login|forgot Auth form matches
conversations:empty Customer has no conversations

State-Driven Panels (Auto-Hidden)

Hidden by default. cStar reveals them when the state matches.

Attribute Behavior
data-cstar-panel Wrap your whole chat panel — toggles with open/close. Sets data-open="true|false" for CSS hooks
data-cstar-loading Visible while a request is in flight
data-cstar-error Visible when an error message is set. Inner [data-cstar-error-text] receives the message
data-cstar-error-text Receives the latest error message as textContent
data-cstar-empty Visible when the conversation list is empty
data-cstar-agent-typing Visible while an agent is typing
data-cstar-attachment-preview Visible while a file is staged. Inner [data-cstar-attachment-name] shows the filename
data-cstar-attachment-name Receives the staged attachment's filename
data-cstar-notifications-prompt Visible only while browser notification permission is default

Conversation List

Define the list and its row template:

<div data-cstar-conversations>
  <template data-cstar-conversation-template>
    <div data-cstar-conversation>
      <span data-cstar-title></span>
      <span data-cstar-preview></span>
      <span data-cstar-time></span>
      <span data-cstar-unread></span>
    </div>
  </template>
</div>
<div data-cstar-empty>No conversations yet.</div>

Per-row attributes cStar populates inside the template:

Attribute Content
data-cstar-conversation The row root. cStar adds data-conversation-id and binds a click → opens the conversation
data-cstar-title Conversation subject
data-cstar-preview Latest-message preview
data-cstar-time Relative timestamp
data-cstar-unread Unread badge content

Message List

Define the container plus one or two templates (one per role):

<div data-cstar-messages>
  <template data-cstar-message-template="agent">
    <div data-cstar-message>
      <img data-cstar-avatar />
      <span data-cstar-agent-name></span>
      <div data-cstar-content></div>
      <div data-cstar-attachments></div>
      <span data-cstar-time></span>
      <span data-cstar-message-status="sending"></span>
      <span data-cstar-message-status="sent"></span>
      <span data-cstar-message-status="failed"></span>
      <button data-cstar-message-retry>Retry</button>
    </div>
  </template>

  <template data-cstar-message-template="customer">
    <div data-cstar-message>
      <div data-cstar-content></div>
      <div data-cstar-attachments></div>
      <span data-cstar-time></span>
    </div>
  </template>
</div>

Per-message attributes:

Attribute Content
data-cstar-message The message row root
data-cstar-content Rendered message body (markdown for agent messages)
data-cstar-attachments Container cStar fills with attachment chips
data-cstar-time Relative timestamp
data-cstar-avatar Receives src for the agent avatar
data-cstar-agent-name Agent display name
data-cstar-message-status="sending|sent|failed" Shown only when status matches
data-cstar-message-retry Click to retry a failed message

JavaScript API (window.CStarChat)

The SDK is exposed globally once the module loads. Calls made before load are queued.

// Panel
CStarChat.open();
CStarChat.close();
CStarChat.toggle();
CStarChat.isOpen();

// Identity
await CStarChat.signup({ email, name, password });
await CStarChat.login({ email, password });
await CStarChat.magicLink({ email });
await CStarChat.forgotPassword({ email });
CStarChat.identify({ email, name, customer_id });
CStarChat.verifyIdentity(customer, signature, testMode);
CStarChat.logout();
CStarChat.isIdentified();
CStarChat.getCustomer();

// Conversations
await CStarChat.startConversation({ subject, message });
CStarChat.openConversation(conversationId);
CStarChat.deleteConversation(conversationId);
CStarChat.getConversations();
CStarChat.getCurrentConversation();

// Messaging
CStarChat.send('Hello!');
CStarChat.attachFile(file);
CStarChat.removeAttachment();
CStarChat.getAttachment();

// Views & Forms
CStarChat.showView('conversations'); // or 'messages' | 'auth' | 'new' | 'offline'
CStarChat.getCurrentView();
CStarChat.showAuthForm('login');     // or 'signup' | 'forgot'
CStarChat.getAuthForm();

// Drafts (for headless input handling)
CStarChat.setDraft(value);
CStarChat.setSubject(value);
CStarChat.setAuthEmail(value);
CStarChat.setAuthName(value);
CStarChat.setAuthPassword(value);

// State
CStarChat.getUnreadCount();
CStarChat.getConnectionStatus();
CStarChat.isOnline();
CStarChat.isSoundEnabled();
CStarChat.setSoundEnabled(true);
CStarChat.requestNotifications();

// Knowledge Base
await CStarChat.searchArticles('billing', 5);
await CStarChat.getArticle('api-authentication');
await CStarChat.getPopularArticles(5);
await CStarChat.getCategories();
await CStarChat.getLibraryStats();

// Lifecycle
CStarChat.refresh();
CStarChat.destroy();

Events (CStarChat.on)

CStarChat.on('ready', () => { /* widget loaded */ });
CStarChat.on('open', () => { /* panel opened */ });
CStarChat.on('close', () => { /* panel closed */ });
CStarChat.on('identify', (customer) => { /* logged in */ });
CStarChat.on('logout', () => { });
CStarChat.on('view', (viewName) => { });
CStarChat.on('connection', (status) => { /* connected | connecting | reconnecting | offline */ });
CStarChat.on('online', (isOnline) => { });
CStarChat.on('unread', (count) => { });
CStarChat.on('message', (msg) => { /* any message */ });
CStarChat.on('message:received', (msg) => { /* from agent */ });
CStarChat.on('message:sent', (msg) => { /* from customer */ });
CStarChat.on('messages', (allMessages) => { });
CStarChat.on('conversations', (allConversations) => { });
CStarChat.on('conversation:open', (conversation) => { });
CStarChat.on('typing', (isTyping) => { });
CStarChat.on('attachment:complete', (attachment) => { });
CStarChat.on('attachment:removed', () => { });
CStarChat.on('loading', (isLoading) => { });
CStarChat.on('error', (error) => { });
CStarChat.on('session:expired', () => { });

// Unsubscribe
CStarChat.off('message', handler);

Tips

  1. Wrap your panel in data-cstar-panel so open/close just works.
  2. Templates beat manual rendering — let the binder handle conversation rows and message bubbles.
  3. data-cstar-show-when covers most state branches without writing JavaScript.
  4. Keep clickable elements at least 42px tall for mobile.
  5. Agent message content is markdown — render with marked or similar if you're not using the templates.
  6. New DOM mounted after page load is auto-bound. No bind() call needed.