@qentrah/chat-components
v0.1.0
Published
Reusable React chat components with scoped styles, optional motion, and agent adapters
Maintainers
Readme
Grok Chat Components
Reusable React and TypeScript components for a responsive chat interface inspired by Grok. Use the complete screen, embed the controlled composer, or combine individual components with your own agent backend.
Built with React 19, Tailwind CSS 4, Motion, and Lucide icons. Animations are optional and disabled by default.

Features
- Responsive desktop and mobile layouts with a bottom-positioned mobile composer.
- Controlled message input, slash-command suggestions, and file attachment callbacks.
- Configurable response modes, branding, navigation links, and welcome text.
- Light, dark, and system appearance settings.
- Optional menu animation and placeholder rotation, respecting reduced-motion preferences.
- An asynchronous send adapter for connecting an agent or chat service.
- Scoped component styles, keyboard focus indicators, and a privacy dialog with focus trapping.
The included application is a local demonstration. It displays an explicit demo response and does not call an AI provider or upload attachments. Connect your backend through onSend to enable real agent responses.
Run the demo
Use a Node.js version supported by the installed Vite release and npm.
git clone https://github.com/Up-to-code/grok-chat-components.git
cd grok-chat-components
npm ci
npm run devOpen the local URL printed by Vite, normally http://localhost:5173.
npm run build # Production output in dist/
npm run preview # Preview the production build locallyRepository access is required to clone this private project.
Install the npm package
The package name is @qentrah/chat-components. Once published to the npm registry:
npm install @qentrah/chat-componentsThe packed release can also be installed directly without a registry login:
npm install ./qentrah-chat-components-0.1.0.tgzReact and React DOM 18.2+ or 19 are peer dependencies. The package supplies compiled, scoped CSS, embedded SVG icons and fonts, TypeScript declarations, and ESM/CommonJS exports. Consumers do not need Tailwind CSS, a Tailwind build plugin, or manual asset copying. Import the stylesheet once in your app entry or global stylesheet entry:
import { GrokInterface } from '@qentrah/chat-components';
import '@qentrah/chat-components/styles.css';
export default function App() {
return (
<GrokInterface
brand="My Agent"
title="How can I help?"
motionEnabled={false}
modes={[{ name: 'Fast' }, { name: 'Expert' }]}
upgradeLabel=""
links={{
signIn: '/login', signUp: '/register', imagine: '/images',
terms: '/terms', privacy: '/privacy', feedback: '/support',
}}
/>
);
}This renders the screen without inventing assistant replies. Connect onSend to your backend as shown below. React Server Component frameworks should render these components in a client boundary; the JavaScript package exports include a use client directive. Server rendering and Node imports do not require a browser at import time.
Individual pieces are also importable:
import { Composer, InterfaceFrame, Conversation } from '@qentrah/chat-components';Composer is controlled through value, onChange, and onSubmit; pass attachment and onAttachmentChange when managing uploads. See the component guide for complete examples or for copying the original source instead of installing the package.
Connect an agent backend
onSend receives a SendRequest and returns a text reply. The component appends the user's message, disables submission while the request is pending, and displays the returned assistant response.
type SendRequest = {
text: string;
mode: string;
attachment: File | null;
};A backend adapter can send these fields to your own endpoint:
import { GrokInterface, type SendRequest } from '@qentrah/chat-components';
async function sendToAgent(request: SendRequest): Promise<string> {
const form = new FormData();
form.set('text', request.text);
form.set('mode', request.mode);
if (request.attachment) form.set('attachment', request.attachment);
const response = await fetch('/api/chat', {
method: 'POST',
body: form,
});
if (!response.ok) throw new Error('Agent request failed');
const data = await response.json();
if (typeof data.reply !== 'string') {
throw new Error('Expected a text reply');
}
return data.reply;
}
export default function AgentChat() {
return (
<GrokInterface
onSend={sendToAgent}
modes={[{ name: 'Fast' }]}
upgradeLabel=""
privacyDescription="Messages are sent to our agent service."
/>
);
}Implement /api/chat on your server. It should parse the multipart form, run your agent, and return { "reply": "Your agent's answer" }. Keep provider credentials on the server. For conversation memory, associate requests with a conversation ID in your adapter and backend; the component does not send its full message history.
If the adapter throws, the interface shows an error and restores the draft and attachment. The current adapter supports complete text replies rather than streaming tokens.
Component reference
All components and public types are exported from src/components/grok/index.ts.
| Export | Purpose |
| --- | --- |
| GrokInterface | Complete screen with drafts, menus, attachments, and conversation state |
| Composer | Controlled input with send, attachment, mode, and slash-command controls |
| Conversation | User and assistant message display |
| Header | Brand mark, account links, and settings trigger |
| ModeMenu | Configurable response modes and optional sign-in links |
| SettingsMenu | Appearance, language, and animation controls |
| Footer | Legal links and privacy trigger |
| PrivacyDialog | Privacy preferences with keyboard focus trapping |
| InterfaceFrame | Scoped theme, typography, and motion settings |
Wrap individually composed pieces in InterfaceFrame to provide their theme variables. Some components retain the reference screen's fixed or absolute positioning; adjust layout classes when embedding them into another layout.
See UsageExamples.tsx for static, animated, controlled-composer, and backend-adapter examples.
Main interface options
| Prop | Behavior |
| --- | --- |
| onSend | Agent adapter; returns a string, void, or a promise of either |
| brand, title | Labels and welcome heading |
| links | Overrides navigation, account, legal, and feedback destinations |
| modes | Response choices; requiresSignIn marks a choice as an account link |
| initialMessages | Messages loaded when the component mounts |
| motionEnabled | Initial animation preference, off by default; updates also synchronize it |
| onMotionChange | Reports changes from the Animations setting |
| placeholders | Composer hints; rotation occurs only when motion is enabled |
| assetBase | Prefix for icon paths; font paths are configured in styles.css |
| conversationNotice, attachmentNotice, privacyDescription | Application-specific explanatory text |
| upgradeLabel | Upgrade label; an empty string hides the upgrade panel |
Appearance and motion

Use motionEnabled={true} to start with animations enabled. Users can change this in Settings. Turning motion off disables menu animation, CSS transitions, and placeholder rotation. Operating-system reduced-motion preferences take precedence.
The textarea has no inner focus outline. A subtle border on the outer composer indicates focus, while buttons retain visible keyboard focus styles. Enter submits, Shift+Enter inserts a line, and IME composition does not trigger submission.
Project structure
src/
components/grok/ Reusable components, styles, types, and examples
pages/Clone.tsx Local demo wrapper and demo response
main.tsx Demo entry point
index.css Demo Tailwind configuration
lib/ Generated npm library output (not tracked)
public/
icons/ Reference SVG assets
fonts/ Reference font files
docs/screenshots/ Interface screenshots used in this READMEPackage builds and releases
npm ci
npm run typecheck
npm run build:lib # Library JavaScript, CSS, and declarations in lib/
npm run build # Standalone demo in dist/
npm pack # Installable .tgz archive; builds the library firstThe npm archive includes the library, package metadata, and README. It excludes the demo, .openai/hosting.json, Git metadata, screenshots, and development dependencies. React is externalized so the host application supplies a single React instance. Motion and Lucide are normal runtime dependencies.
Authorized maintainers can publish a version after verification with npm publish --access public. Registry sign-in and any required two-factor verification must be completed by the publisher. The prepare script also builds the library for Git-based installation; the prebuilt npm tarball does not need consumer-side build tooling.
The repository declares UNLICENSED (all rights reserved); public npm availability does not add an open-source license.
Scope and verification
The demo stores conversations and appearance preferences in page memory. It includes no authentication backend, message persistence, agent runtime, streaming, or attachment processing. Default account and Imagine links point to Grok; override them for your application. Slash commands insert text hints and require interpretation by your agent if you want them to perform actions.
The component code and usage examples passed TypeScript checks and the production build. Browser checks covered desktop and mobile layout, composer focus styling, animation toggling, menus, local submission, and privacy-dialog keyboard behavior. Screenshots show the local demo, not a live AI response.
This is an independent interface study inspired by Grok, with no affiliation with xAI. Bundled reference branding and assets retain their respective ownership.
