Chat Kit
Full-featured iMessage/WhatsApp-inspired chat with 1-1 and group conversations, attachments, polls, GIFs, location sharing, reactions, and Socket.IO real-time transport.
Quick reference
CLI commands
# Add Chat UI components
npx @fivfold/ui add chat
# Add Chat backend (NestJS + TypeORM + Socket.IO)
npx @fivfold/api add chat --framework=nestjs --orm=typeorm
# Use MongoDB + Mongoose
npx @fivfold/api add chat --framework=nestjs --orm=mongoose
# Use Express + Prisma
npx @fivfold/api add chat --framework=express --orm=prisma
# Dry run to preview generated files
npx @fivfold/ui add chat --dry-run
npx @fivfold/api add chat --dry-runOverview
The Chat Kit is a production-ready messaging system scaffolded across your full stack. It follows Hexagonal Architecture so you can swap databases, ORMs, and real-time providers without touching your domain logic. Supported combinations:
| Layer | Options |
|---|---|
| Framework | NestJS, Express |
| SQL | TypeORM (PostgreSQL, MySQL, MariaDB, MSSQL), Prisma |
| NoSQL | Mongoose (MongoDB), Prisma (MongoDB connector) |
| Cloud NoSQL | Azure Cosmos DB SDK, AWS DynamoDB SDK |
| Realtime | Socket.IO (WebSocket — auto-selected) |
1-1 & Group Chats
Private DMs and multi-participant group conversations with admin roles, member management, and leave/remove actions.
Rich Messages
Text, images, videos, files, audio, GIFs (Tenor API), location pins, and interactive polls — all sent as typed message variants.
Real-time Updates
Socket.IO WebSocket rooms with typing indicators, presence detection, read receipts, and message delivery events — works with any database.
Reactions & Read Receipts
Per-message emoji reactions, per-message read-by tracking, and animated typing indicators with user avatars.
Search
Full-text search across conversations and message content with paginated results grouped by type.
Glassmorphism UI
Backdrop-blur message bubbles, smooth framer-motion animations, and fully responsive layout from mobile to desktop.
Architecture
The Chat Kit backend strictly follows Hexagonal (Ports & Adapters) Architecture. The domain port (IChatService) is framework and database agnostic — the delivery and infrastructure layers are generated separately based on your stack selection.

Demo
Interactive preview with simulated real-time replies and mock data
Sarah Johnson
Online
Shared Media
Guide
Step-by-step guides for the frontend UI and backend API integration. Select your stack in the API tab to see stack-specific instructions.
The Chat Kit UI is built on shadcn/ui with Tailwind CSS v4. All components are fully customizable and support light/dark mode via CSS variables.
1Install the Chat Kit
Run the FivFold UI CLI after initializing your project with npx @fivfold/ui init.
npx @fivfold/ui add chatComponents are placed in @/components/ui/kits/chat/. Additional npm packages (framer-motion, date-fns, emoji-mart) are installed automatically.
2Generated file structure
kits/chat/
types.ts # All shared TypeScript types
index.tsx # ChatKit root component + re-exports
chat-avatar.tsx # ChatAvatar, GroupAvatar
threads-list.tsx # Sidebar conversation list
thread-item.tsx # Individual thread row with context menu
conversation.tsx # Message view with infinite scroll
message-bubble.tsx # Message bubble (text, image, poll, location, GIF)
message-input.tsx # Compose bar with attachment/GIF/poll/location
typing-indicator.tsx # Animated typing dots
attachment-picker.tsx # File/image/video picker with drag-and-drop
gif-picker.tsx # Tenor GIF search and picker
poll-creator.tsx # Create poll dialog
poll-display.tsx # Rendered poll with vote progress
location-picker.tsx # Share location (geolocation or manual)
location-display.tsx # Static map + Google Maps link
reaction-picker.tsx # Quick emoji reaction overlay
search-panel.tsx # Full-text search dialog
new-chat-dialog.tsx # Start DM or create group dialog
contact-detail.tsx # Contact info sheet
group-detail.tsx # Group info, members, admin controls3Import and use in your app
import { ChatKit } from "@/components/ui/kits/chat";
import type {
FivFoldChatConversation,
FivFoldChatMessage,
FivFoldChatUser,
} from "@/components/ui/kits/chat";
export default function ChatPage() {
const currentUser: FivFoldChatUser = {
id: "u1",
name: "You",
email: "you@example.com",
};
return (
<ChatKit
currentUser={currentUser}
conversations={conversations}
onSendMessage={handleSendMessage}
onCreateConversation={handleCreate}
onVotePoll={handleVote}
onAddReaction={handleReaction}
onMarkRead={handleMarkRead}
/>
);
}4ChatKit props reference
| Prop | Type | Purpose |
|---|---|---|
| currentUser | FivFoldChatUser | The logged-in user. Used to determine sent/received and show own avatar. |
| conversations | FivFoldChatConversation[] | All conversations to display in the sidebar thread list. |
| onSendMessage | (convId, dto) => void | Called when user sends any message type (text, attachment, poll, location, GIF). |
| onCreateConversation | (dto) => Promise<Conversation> | Called when user starts a new DM or group. Return the created conversation. |
| onVotePoll | (pollId, optionIds) => void | Called when user votes on a poll. PATCH /api/chat/polls/:id/vote. |
| onAddReaction | (msgId, emoji) => void | Called when user reacts to a message. POST /api/chat/messages/:id/reactions. |
| onMarkRead | (msgId) => void | Called when a message enters the viewport. PATCH /api/chat/messages/:id/read. |
| typingUsers | Record<string, string[]> | Map of convId → userIds currently typing. Drives the animated typing indicator. |
| onTyping | (convId, isTyping) => void | Emit typing start/stop events to your real-time backend. |
| loadingMessages | boolean | Show skeleton loaders while fetching message history. |
| hasMoreMessages | boolean | Enable the "load more" trigger at the top of the message list. |
| onLoadMore | () => void | Called when user scrolls to the top. Fetch the next page of messages. |
shadcn dependencies
| Component | Used in |
|---|---|
| button | Throughout |
| input | Search, compose, group name edit |
| dialog | GIF picker, poll creator, attachment picker, search, new chat |
| sheet | Contact detail, group detail panels |
| scroll-area | Thread list, message list, member list |
| context-menu | Thread item actions, message actions |
| badge | Unread count, admin role |
| separator | Section dividers |
| tabs | New chat dialog (DM / Group) |
| switch | Poll allow-multiple-answers toggle |
| progress | Poll vote percentage bars |
| alert-dialog | Leave group confirmation |
| tooltip | Reaction counts, action hints |
5Third-party integrations
The Chat Kit UI integrates with external services for GIFs, file uploads, and location sharing. Configure these in your frontend; the API supports the corresponding message types (see API tab).
Tenor GIF integration
Tenor (by Google) provides a GIF search API. The gif-picker.tsx component calls Tenor directly for search; when the user selects a GIF, it sends a message via onSendMessage with type: "gif" and metadata: { tenorId, url, previewUrl, ... }.
Flow: (1) User opens GIF picker → frontend calls Tenor Search API with query. (2) User selects GIF → call onSendMessage(convId, { type: "gif", metadata: { tenorId, url, previewUrl, description } }). (3) Your backend receives POST /api/chat/conversations/:id/messages and creates the message. (4) Optionally call Tenor's Register Share endpoint when a GIF is sent to improve future search results.
// gif-picker.tsx — Tenor Search (frontend)
const res = await fetch(
`https://tenor.googleapis.com/v2/search?q=${query}&key=${TENOR_API_KEY}&client_key=my_app&limit=8&media_filter=tinygif,gif`
);
const data = await res.json();
// Use tinygif for previews, gif for the URL sent in metadataSetup: Create an API key in Google Cloud Console and enable the Tenor API. Use NEXT_PUBLIC_TENOR_API_KEY for client-side search, or proxy Tenor through your backend. Include client_key in all requests. Tenor requires attribution — see their attribution guide.
File storage (attachments)
The attachment-picker.tsx lets users select files. Attachments are stored in object storage — not in your database. Your frontend must upload the file first, then call onSendMessage (or your attachment endpoint) with the resulting URL.
- User selects file → upload to S3, GCS, R2, or your backend proxy (presigned URLs, etc.).
- On upload complete → call your API with
url,name,size,mimeType. - Backend creates Message + Attachment; UI displays via
message-bubble.tsx.
Recommended: AWS S3, Google Cloud Storage, Cloudflare R2, or Azure Blob. Generate thumbnails for videos and pass thumbnailUrl for faster rendering.
Location sharing
The location-picker.tsx and location-display.tsx components handle sharing and display. Use navigator.geolocation.getCurrentPosition() to obtain coordinates, or allow manual input. Send via onSendMessage with type: "location" and metadata: { latitude, longitude, label? }.
No external API required. location-display.tsx can use OpenStreetMap for the preview and link to Google Maps for "Open in Maps".
