qalainau/filament-team-chat
Slack-like team chat inside Filament v5: channels, DMs, threads, reactions, @mentions, file sharing, search, and unread tracking. Self-hosted with no external services—works via Livewire polling. Multi-tenant ready with optional team scoping.
A complete Slack-like team chat for Filament v5. Drop it into any panel — channels, DMs, threads, reactions, mentions, file sharing, search, and unread tracking work out of the box. Self-hosted, no external services needed.

team_id scoping with automatic Filament tenant detection.code, lists, and links@user, @channel, @here with live autocompleteteam_id scoping with Filament tenant auto-detectioncomposer require qalainau/filament-team-chat
Publish and run the migrations:
php artisan vendor:publish --tag=team-chat-migrations
php artisan migrate
use Filament\TeamChat\FilamentTeamChatPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentTeamChatPlugin::make());
}
use Filament\TeamChat\Concerns\HasTeamChat;
class User extends Authenticatable
{
use HasTeamChat;
}
Required for @mention and DM notifications:
php artisan make:notifications-table
php artisan migrate
The plugin uses Tailwind CSS classes that must be included in your Filament theme.
If you don't have a custom theme yet, create one first:
php artisan filament:theme
Then add the package views as a source in your theme file:
/* resources/css/filament/admin/theme.css */
@source '../../../../vendor/qalainau/filament-team-chat/resources/views/**/*';
Build the theme:
npm run build
Done! Visit /admin/team-chat to start chatting.
Publish the config file:
php artisan vendor:publish --tag=team-chat-config
// config/team-chat.php
return [
'table_prefix' => 'tc_',
'user_model' => \App\Models\User::class,
'polling' => [
'messages' => 3, // seconds
'sidebar' => 5, // seconds
],
'uploads' => [
'disk' => 'public',
'directory' => 'team-chat-attachments',
'max_size' => 10240, // KB
],
'tenancy' => [
'enabled' => false,
'model' => null, // e.g. \App\Models\Team::class
'resolver' => null, // null = Filament::getTenant()
],
];
Set tenancy.enabled to true to scope channels and conversations per team. The resolver supports:
| Mode | Config | Behavior |
|---|---|---|
| Auto (default) | null |
Uses Filament::getTenant() |
| Callable | fn () => auth()->user()->team_id |
Custom closure |
| Class | TenantResolver::class |
Must have resolve() method |
All features are available as PHP classes — useful for seeders, commands, or integrations.
use Filament\TeamChat\Models\Channel;
// Create a channel
$channel = Channel::create([
'name' => 'general',
'slug' => 'general',
'type' => 'public', // or 'private'
'created_by' => $user->id,
]);
$channel->members()->attach($user->id, ['role' => 'owner']);
// DMs (idempotent — returns existing conversation if found)
$dm = $user->findOrCreateDirectMessage($otherUser->id);
// Group DM
$group = $user->createGroupConversation(
userIds: [$user2->id, $user3->id],
name: 'Project Team',
);
use Filament\TeamChat\Actions\SendMessage;
$message = app(SendMessage::class)->execute(
messageable: $channel, // Channel or Conversation
userId: $user->id,
body: 'Hello @Jordan! Check this **bold** text.',
parentId: null, // set for thread replies
files: [], // array of UploadedFile
);
use Filament\TeamChat\Actions\{ToggleReaction, MarkAsRead, SearchMessages};
// Toggle reaction (returns true=added, false=removed)
app(ToggleReaction::class)->execute($message->id, $user->id, '👍');
// Unread count
$channel->unreadCountFor($user->id); // => 3
// Mark as read
app(MarkAsRead::class)->execute($channel, $user->id);
// Search (respects channel/DM membership)
$results = app(SearchMessages::class)->execute($user->id, 'deploy', limit: 20);
All tables use a configurable tc_ prefix:
| Table | Purpose |
|---|---|
tc_channels |
Public/private channels (optional team_id) |
tc_channel_user |
Channel membership pivot with roles |
tc_conversations |
1-on-1 and group DMs (optional team_id) |
tc_conversation_user |
DM participant pivot |
tc_messages |
Polymorphic messages (Channel or Conversation) |
tc_reactions |
Emoji reactions per message per user |
tc_attachments |
File metadata (name, path, MIME, size) |
tc_mentions |
@user / @channel / @here per message |
tc_read_receipts |
Per-user last-read tracking (polymorphic) |
tc_user_statuses |
Online status, display name, custom status |
| Component | Role | Updates |
|---|---|---|
Sidebar |
Channel/DM list, unread badges, create/join | 5s poll + event |
MessageFeed |
Messages, reactions, edit/delete, reply | 3s poll + event |
MessageComposer |
Input, file upload, @mention autocomplete | on submit |
ChannelHeader |
Name, topic, members, settings, archive | on event |
ThreadPanel |
Threaded replies with own composer | 3s poll |
SearchModal |
Full-text search across channels/DMs | on input |
MemberList |
Member list with online status | on open |
UserProfileCard |
Profile popup with DM shortcut | on open |
# Run in the package directory
composer test
# Or in your Laravel app
php artisan test --filter=TeamChat
102 tests covering channels, DMs, threads, reactions, mentions, attachments, search, read receipts, notifications, user status, and channel management.
Please see CHANGELOG for more information on what has changed recently.
The MIT License (MIT). Please see License File for more information.
How can I help you explore Laravel packages today?