Download the PHP package asignua/filament-chat without Composer

On this page you can find all versions of the php package asignua/filament-chat. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package filament-chat

Filament Chat

Stand With Ukraine Latest Version on Packagist Tests Total Downloads License Plumb score

Filament Chat

Team chat for Filament panels. Direct messages and groups, @mentions, editing, reactions, read receipts, a slide-over you can pin next to any page — and messages that point at your panel's records: drag a link to a record into the chat and it becomes a card.

Works with or without a websocket server: turn real-time on with one environment variable (Laravel Reverb, Pusher, Ably), or let the chat poll.

Screenshots

The Chat page — conversations, reactions, read receipts and record cards:

The Chat page

The slide-over pinned next to a record page, with "Attach current":

The slide-over next to a record

@mentions with autocomplete:

Mentions

Dark mode:

Dark mode

Features

Conversations Direct messages (one per pair) and groups: title, members, leave. The creator manages a group; whoever leaves keeps the history up to that moment. A member added to a group — or added back after leaving — sees its whole history, including what was written while they were away; none of it counts as unread.
@mentions Type @ for the list of members. A mention is highlighted (your own name stands out) and always rings the bell.
Editing ✏️ on your message or ↑ in an empty composer; edited messages are marked. Optional time window.
Reactions Six emoji, one per person per message.
Read receipts ✓ sent, ✓✓ read — in a group, read by every active member (the hint lists who has not).
Replies ↩ on a message quotes it above your answer; a click on the quote jumps to the original, loading earlier messages if needed.
Avatars Next to the last message of a series in groups, in the @ list and the member line; direct conversations in the list always show the person. From Filament's avatar provider or ->avatarUsing(); initials when there is no picture.
New messages Opening a conversation scrolls to a line where the unread part starts (up to five pages back, otherwise it opens at the bottom); sending your own message clears the line.
Record references Attach a record with a picker, by dropping a link to its page, or "Attach current" in the slide-over.
Where A full Chat page and a top-bar button with a slide-over; on wide screens the slide-over can be pinned as a split screen that stays open across pages.
Unread Counters in the navigation, on the button, in the browser tab title and on the favicon; a bell notification on the first unread message of a conversation and on every mention; a "Reply" toast.
Privacy A conversation is visible to its members only — admins included. Messages are never deleted.
Languages English, Ukrainian, German, Spanish, French, Italian, Dutch, Polish, Brazilian Portuguese, Turkish; add yours.

Every feature can be switched off.

Requirements

Installation

filament-chat:install publishes config/filament-chat.php and the migration (4 tables), runs the migrations with --migrate, links the agent skill with --skill and tells you what is left. Bell notifications use Laravel's notifications table — php artisan make:notifications-table if your app does not have it yet.

Register the plugin in your panel provider:

That's it: a Chat page in the navigation and a chat button next to the user menu. The chat polls for news until you turn real-time on.

The stylesheet ships compiled and is linked after your panel's theme — no custom theme and no @source lines are needed. It is published by php artisan filament:assets; if you commit published assets, re-run it after upgrading the package.

Configuration

Every setting lives in config/filament-chat.php (commented — read it once) and can also be set on the plugin, which wins. Closures — who can be written to, how people are called, per-type rules for references — exist on the plugin only, so the config stays cacheable.

Users

Features

Key Plugin Default Off means
features.groups ->groups(false) true direct messages only; "New group" and "Manage group" disappear, the server refuses to create or change groups. Groups that already exist stay in the list and keep working (messages, leaving)
features.reactions ->reactions(false) true no emoji picker or chips; the server refuses reactions
features.mentions ->mentions(false) true no @ autocomplete, nothing highlighted or notified (mentions stored in old messages are not highlighted either)
features.read_receipts ->readReceipts(false) true no ✓ / ✓✓
features.avatars ->avatars(false) true no pictures or initials next to messages, in the @ list or the member line
features.replies ->replies(false) true no ↩ button and no new quotes; quotes already stored stay visible
features.editing.enabled / .window ->editing(true, 15) true, null no editing; window — minutes after sending, null — any time

Switching a feature off never deletes data.

Messages

Interface

Key Plugin Default
ui.dock ->dock(false) true — the top-bar button and slide-over; off: the Chat page only
ui.pinnable ->pinnable(false) true — "pin" the slide-over as a split screen (from lg)
ui.tab_badge ->tabBadge(false) true — unread count in the tab title and on the favicon
ui.color ->color('fuchsia') primary — group avatars and author names
ui.slug ->slug('messages') chat
ui.navigation.group / .sort / .icon ->navigationGroup() / ->navigationSort() / ->navigationIcon() null / 90 / chat bubbles

->navigationGroup() and ->navigationIcon() also accept enums and closures (translated group names).

Record references

A message may point at a record of your panel — an order, a customer, a page. It shows as a card with the record's icon, type and title, linking to its page.

Which records

Register resources on the plugin:

From the resource the chat takes the label, icon, record title, the link (the edit page for those who may edit, the view page for the rest) and the search of the picker (the globally searchable attributes). Everything can be overridden:

The key (invoice; order for ReferenceType::resource(OrderResource::class)) is stored with the message — keep it stable.

Or every resource at once — no list to maintain:

With "all resources" the key is the resource slug (orders, activity-log/activity-logs): renaming a slug loses the link of old messages (they show "record deleted"). Register a type explicitly where that matters.

Only models with an integer primary key can be referenced (the message stores the id in an integer column). "All resources" skips models keyed by a UUID/ULID string, and registering one explicitly throws an InvalidArgumentException. A ULID used only as the route key (with an integer id) is fine.

'references' => ['enabled' => false] turns references off completely.

Who sees a referenced record

A viewer who may not see the record gets its type only — no title, no link — and cannot attach it. "May see" is references.authorize (or ->authorizeReferences() on the plugin):

Value Rule A model without a policy
'policy' (default) the model's view policy hidden
'resource' the resource's canView() — Filament's own rule visible to everyone in the panel
false no check visible

Watch out. Filament shows a resource whose model has no policy, but Laravel's Gate denies an ability nobody defined. With the default 'policy', records of such a resource are visible in the panel yet can never be attached — dropping a link says so. Either add a policy (view → true for a read-only resource) or switch to 'resource'. A type's ->visibleUsing() beats both.

Attaching

Discuss in chat

A header action for record pages — to whom (a person or a group I am in) and the text; the record is attached:

It shows only for records of a referenceable type; it works as a table row action too.

Real-time delivery

The chat works both ways — pick per environment:

FILAMENT_CHAT_REALTIME Behaviour
false polling: an open conversation every 15 s, the unread counter every 60 s (polling.*)
true new messages, reads, reactions and group changes arrive instantly; toasts appear on any page
unset (null) on when the default broadcaster is reverb, pusher or ably

Events carry identifiers only; the components re-read the data, so policies — not the socket payload — decide what anyone sees. Each person listens on a private channel filament-chat.user.{key}, authorised by the package. Events are broadcast immediately (ShouldBroadcastNow) — no queue worker needed; if the socket is down the message is still saved and the counters catch up by polling.

Laravel Reverb

That is all: by default (realtime.echo = 'plugin') the plugin brings Laravel Echo itself — it reuses the Echo that Filament already ships — configured from the broadcasting connection. It also registers /broadcasting/auth if your app has not (realtime.register_auth_route).

Where the browser connects. PHP publishes to REVERB_HOST:REVERB_PORT; the browser connects to the page's own host, protocol and default port unless told otherwise:

Pusher / Ably / another connection

Any Pusher-compatible connection works the same way (BROADCAST_CONNECTION=pusher). Pusher Channels (cloud) is addressed by its cluster from broadcasting.connections.pusher.options.cluster. To publish chat events on a connection other than the app's default: FILAMENT_CHAT_BROADCAST_CONNECTION=reverb.

Your own Echo

If your app already loads window.Echo (a Vite bundle), or you configured Filament's filament.broadcasting.echo, set FILAMENT_CHAT_ECHO=host or =filament — the plugin then only subscribes. An existing window.Echo is never replaced.

Notifications

Key Default
notifications.database true the bell: the first unread message of a conversation (the rest only grow the counter) and every mention. Needs ->databaseNotifications(), the notifications table and Notifiable on the user model.
notifications.toasts true a "Reply" toast for a message in another conversation (real-time only)

Translations

The chat follows your app's locale and ships with English, Ukrainian, German, Spanish, French, Italian, Dutch, Polish, Brazilian Portuguese and Turkish. Every string lives in one file per language, e.g. resources/lang/en/chat.php; dates use the same locale (month names come from Carbon).

Another language — create lang/vendor/filament-chat/{locale}/chat.php in your app with the same keys (copy the English file and translate it):

Change a few phrases — the same file with only the keys you want to change; the rest still comes from the package:

Copy all package translations to edit them:

Translated the chat into your language? A pull request with resources/lang/{locale}/chat.php is very welcome.

Upgrading from 1.1

1.2 adds one column (reply_to_id, replies) in a second migration, add_reply_to_filament_chat_messages. Publish and run it:

(php artisan filament-chat:install --migrate does the same: it publishes whatever is missing.)

Without the new migration 1.2 keeps working, but replies stay off until you run it: the package checks for the reply_to_id column.

The published migration reads the table name from tables.messages, so a renamed table is covered. Only if your messages table was not created by the package's published migration (your app made it some other way), add the column yourself, replacing chat_messages with your table name:

Avatars and the "New messages" line need no migration. Don't want avatars or replies? Switch them off (features.avatars, features.replies) — stored quotes stay visible either way.

Customising

Your own models and tables

Swap any model for a subclass and rename the tables before running the migration:

An audit trail

Messages, reactions and read pointers are deliberately not audited — an audit feed would let admins read other people's conversations. For conversations use a subclass with your logging trait, and listen to Asignua\FilamentChat\Events\GroupMembersChanged ($conversation, $before, $after — member names) for membership, which lives in a pivot the model diff cannot see.

Events

Event When
Asignua\FilamentChat\Events\ChatUpdated anything changed in a conversation — broadcast to members
Asignua\FilamentChat\Events\GroupMembersChanged a group was created, its members changed, someone left
Asignua\FilamentChat\Events\MessageSent a message was stored by ChatService::send() ($message) — a plain event, dispatched after the commit

Writing from your code

Always go through ChatService — it stores mentions, broadcasts and notifies, and checks membership where a message is involved (send, edit, react). Group management does not check who asks: updateGroup() changes any group it is given and leave() acts on the user passed in. Authorize before calling them, as the chat's own actions do:

Extending

Seams for add-on packages (attachments, search, typing indicators …) that change the chat window without forking it. Nothing here changes the stock chat.

Your own window

The class must extend Asignua\FilamentChat\Livewire\ChatWindow; it is mounted on the Chat page and in the slide-over. Override these protected methods (all optional):

Method Default Use
canSendWithoutBody(): bool false true lets send() store a message with no text and no record (the content is carried some other way)
beforeMessageCommit(Message $message) no-op runs inside the send transaction — store your own rows; a throw rolls the message back
afterMessageSent(Message $message) no-op after a successful send from this window — reset your own composer state
modifyMessagesQuery(Builder $query): Builder $query shapes every feed query (page, "load older", unread line, jumps, read pointer): eager-load, or withTrashed() for a message model with soft deletes
conversationChanged(?string $from, ?string $to) no-op another conversation was opened (list, toast, search hit) or the person went back to the list ($to null): drop state that belongs to the old one — pending uploads, a draft. Ulids
isMessageTombstone(Message $message): bool false true renders «Message deleted» instead of text, record, reactions, reply/edit/menu — also in a quote of it and in the conversation list preview

openMessage(string $messageUlid) (public) jumps to a message of any of the person's conversations: it opens the conversation first if needed, loads up to the message and flashes it. A message of a conversation the person may not see, or written after they left a group, is ignored.

The message model comes from models.message; a subclass with SoftDeletes works (the free chat adds none). A soft-deleted message is not counted as unread. The MessageRepository reads take an optional trailing ?Closure $scope — that is how modifyMessagesQuery() reaches them.

Render hooks

The closure returns Htmlable, a View, an HTML string or null. The markup is rendered inside the Livewire component, so wire:click reaches the methods of your window subclass and $wire is available to Alpine. $context['conversation'] is the open conversation (null in SIDEBAR_BEFORE without one); the message hooks add message and mine. Give the root element of your markup a wire:key.

Warning — trusted HTML. A string (or Htmlable) is printed as it is. Put user data only into a Blade view ({{ }} escapes), and pass values into wire:click / Alpine expressions with @js(...) or Js::from(...): e() escapes HTML but not a quote inside a JavaScript string.

ChatHook Place
SIDEBAR_BEFORE top of the conversation list, above the search box
HEADER_ACTIONS conversation header, before the group buttons
FEED_BEFORE top of the feed
MESSAGE_BODY_AFTER in the bubble, after the text and the record card
MESSAGE_MENU the buttons beside a bubble
COMPOSER_BEFORE / COMPOSER_AFTER first / last in the composer form
COMPOSER_TOOLS in the input row, right before the send button

Hooks can also be added from an add-on's service provider: app(ChatManager::class)->hooks->register($hook, $closure).

Browser events

The composer dispatches filament-chat-typing on every input and filament-chat-paste (detail.event — the ClipboardEvent, for pasted images) — listen with x-on:filament-chat-typing.window in a hook's markup. Other events are the constants on ChatWindow (EVENT_SCROLL, EVENT_HIGHLIGHT …).

Channels and scripts

The chat only authorizes its own per-person channel. An extension that needs more (a per-conversation typing channel) registers it with plain Laravel — Broadcast::channel('my-ext.conversation.{ulid}', …) — and listens in the browser through the Echo the chat already set up: window.Echo.private(…) (window.Echo exists once the EchoLoaded event fired or when realtime.echo is plugin). Whispers (client events) need them enabled on the socket server. Put the script in a hook's markup (@script / Alpine x-init) or in a panel render hook of your own.

Integration notes

Troubleshooting

Symptom Cause / fix
"… cannot be attached to messages" on a drop the resource is not referenceable — register it or use all_resources
"This link does not lead to a record…" not a record page of this panel (a list, another host)
A record shows its type but "no access" references.authorize = 'policy' and the model has no policy — see Who sees
The slide-over is white on a dark panel stale published assets — php artisan filament:assets
"Laravel Echo cannot be found" in the console real-time is on but no Echo: realtime.echo is host/filament without one, or window.EchoFactory is missing (Filament's core scripts)
Messages arrive only after ~15 s real-time is off (FILAMENT_CHAT_REALTIME), or the socket is not reachable from the browser — check FILAMENT_CHAT_WS_* and the browser's network tab
403 on /broadcasting/auth the user is not logged in on the web guard, or broadcast_key differs between server and channel
No bell notifications ->databaseNotifications() on the panel, the notifications table, Notifiable on the user

AI agents

The package ships a skill for coding agents (Claude Code and others reading .claude/skills) — installation, every option, record references, real-time setups and the traps above:

It lives in resources/boost/skills/filament-chat/SKILL.md, where Laravel Boost looks for package skills.

Testing

License

MIT. See LICENSE.md.


All versions of filament-chat with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
filament/filament Version ^5.0
illuminate/contracts Version ^12.0|^13.0
spatie/laravel-package-tools Version ^1.16
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package asignua/filament-chat contains the following files

Loading the files please wait ...