Sending Messages from Other Scripts
How to send chat messages from your custom scripts.
Basic Usage
Simple Message
TriggerEvent('chat:addMessage', {
args = { "Hello World" }
})
With Author
Using Templates
Registered Template
-- Use a template from Config.Theme
TriggerEvent('chat:addMessage', {
templateId = 'cmd:me',
args = { GetPlayerName(PlayerId()), "does something" }
})
Built-in Presets
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(T.Presets.me()),
args = { GetPlayerName(PlayerId()), "waves" }
})
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(T.Presets.announce('INFO', '#2ecc71', 'rgba(46,204,113,0.12)')),
args = { "Server announcement here" }
})
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(T.Presets.ooc()),
args = { GetPlayerName(PlayerId()), "meta chat" }
})
Getting the Theme Builder
Before building custom templates, get the theme builder export:
local T = exports['chat']:getThemeBuilder()
Custom Inline Template
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(
T.build()
:bg('#1a1a2e')
:tag('CUSTOM', '#00d4ff')
:author({ bold = true })
:text(': ')
:message()
:done()
),
args = { GetPlayerName(PlayerId()), "Custom message" }
})
From Server Scripts
Broadcast to All
-- server/my_script.lua
TriggerClientEvent('chat:addMessage', -1, {
templateId = 'announce',
args = { "Server message to everyone" }
})
Send to Specific Player
TriggerClientEvent('chat:addMessage', targetPlayerId, {
templateId = 'cmd:msg',
args = { "Admin", "You've been warned" }
})
Send to Group
local onlinePlayers = GetPlayers()
for _, playerId in ipairs(onlinePlayers) do
TriggerClientEvent('chat:addMessage', playerId, {
templateId = 'announce',
args = { "Message to all online players" }
})
end
Server-Side Template Resolution
For dont_register: templates, resolve on server:
-- config/templates.lua
Config.Theme['dont_register:job_ad'] = T.build()
:bg('#f39c12')
:text('Job Opening - {Framework.Functions.GetJobLabel}', {
bold = true,
color = '#1a1a1a'
})
:message()
:done()
-- server/job_ads.lua
TriggerClientEvent('chat:addMessage', -1, {
template = resolvedHtml, -- Already processed server-side
args = { "Looking for police officers" }
})
Channels
Send to Channel
TriggerEvent('chat:addMessage', {
templateId = 'cmd:me',
channel = 'police', -- Only police channel members see
args = { GetPlayerName(PlayerId()), "radio message" }
})
Channel Defaults
Commands automatically use their configured channel:
Config.Commands.twitter = {
command = "twitter",
channel = "twitter", -- Uses this channel
}
-- Client-side (auto-channels)
Commands.sendAll('twitter', { GetPlayerName(PlayerId()), message })
Component Argument Mapping
Components consume args sequentially:
local template = T.build()
:tag('TEST') -- Consumes nothing
:author() -- ← consumes args[1]
:text(': ') -- Consumes nothing
:message() -- ← consumes args[2]
:spacer() -- Consumes nothing
:text('Extra info') -- Consumes nothing
:done()
-- args[1] = "PlayerName"
-- args[2] = "This is the message"
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(template),
args = { "PlayerName", "This is the message" }
})
Advanced Examples
Job Announcement
-- server/job_ads.lua
function AnnounceJobOpening(job, message)
local jobLabel = Framework.Functions.GetJobLabel(job)
TriggerClientEvent('chat:addMessage', -1, {
templateId = 'announce:job',
args = { jobLabel .. " - " .. message }
})
end
-- Usage:
AnnounceJobOpening('police', 'Looking for recruits')
Player Action
-- client/my_action.lua
local function PerformAction(action, success)
local template = success and 'cmd:try:success' or 'cmd:try:fail'
TriggerEvent('chat:addMessage', {
templateId = template,
args = { GetPlayerName(PlayerId()), action }
})
end
PerformAction('to pick the lock', true) -- Shows success
PerformAction('to open the safe', false) -- Shows fail
Private Message
-- server/messages.lua
function SendPrivateMessage(fromId, toId, message)
local fromName = Framework.Functions.GetPlayerName(fromId)
TriggerClientEvent('chat:addMessage', toId, {
templateId = 'cmd:msg',
args = { fromName, message }
})
end
System Notification
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(
T.Presets.system('SYSTEM', '#95a5a6', 'rgba(149, 165, 166, 0.12)')
),
args = { "Server is restarting in 5 minutes" }
})
Dispatch Message
TriggerClientEvent('chat:addMessage', -1, {
template = HTML.createTemplate(
T.Presets.announce('DISPATCH', '#e74c3c', 'rgba(231, 76, 60, 0.12)')
),
args = { "Traffic incident at location" }
})
Multi-Line Message
TriggerEvent('chat:addMessage', {
args = { "Admin", "Line 1\nLine 2\nLine 3" }
})
Exports
Use exports instead of events:
-- Send via export
exports['chat']:addMessage({
args = { "Player", "Message" }
})
-- From server
exports['chat']:sendAll({
templateId = 'announce',
args = { "Announcement" }
})
Important Notes
Args Consumption
Not all components consume args:
Consumes args:
T.author()- uses next argT.message()- uses next arg
Does NOT consume args:
T.tag(text)- staticT.text(content)- staticT.icon(svg)- staticT.spacer()- staticT.bold(),T.italic()- static
Placeholder Processing
- Client templates: placeholders replaced on client
- Server templates (
dont_register:): placeholders replaced on server - Framework values: requires framework to be loaded
Template ID vs Template
templateId- Use registered template fromConfig.Themetemplate- Inline template (must useHTML.createTemplate())
Don't mix them:
-- ✓ Correct
TriggerEvent('chat:addMessage', {
templateId = 'cmd:me', -- Uses Config.Theme['cmd:me']
args = { ... }
})
-- ✓ Correct
TriggerEvent('chat:addMessage', {
template = HTML.createTemplate(T.build()...), -- Inline
args = { ... }
})
-- ✗ Wrong - don't use both
TriggerEvent('chat:addMessage', {
templateId = 'cmd:me',
template = HTML.createTemplate(...), -- Conflict!
args = { ... }
})
Backward Compatibility
Still works (legacy format):
TriggerEvent('chatMessage', 'PlayerName', 'msg', message)
But presets are recommended for new code.