joypixels/emoji-toolkit
JoyPixels Emoji Toolkit is a PHP library for working with emoji in web and PHP projects: convert shortnames to Unicode or images, parse emoji in text, and render JoyPixels assets consistently.
composer require joypixels/emoji-toolkit
This is not a Laravel package — there is no service provider, no facade, no publishable config. It is a plain PHP library (JoyPixels\Client, historically Emojione\Client in older trees). Expect to wire everything yourself.
Where to look first:
vendor/joypixels/emoji-toolkit/ and read the Client class. Every option is a public property, and the conversion methods are the API surface:
toImage($str) — unicode/shortname → <img> tagstoShort($str) — unicode → :shortname:shortnameToUnicode($str), unicodeToShortname($str)shortnameToImage($str), unicodeToImage($str)public/.NOASSERTION; JoyPixels ships under its own free-use license with attribution requirements and commercial restrictions.Minimal setup — publish the assets:
# adjust the source path to whatever the package ships
cp -r vendor/joypixels/emoji-toolkit/assets/emoji public/emoji
Register a singleton so you configure it once (app/Providers/AppServiceProvider.php):
use JoyPixels\Client;
$this->app->singleton(Client::class, function () {
$client = new Client();
$client->imageType = 'svg'; // 'png' or 'svg'
$client->imagePathSVG = '/emoji/'; // URL prefix, not a filesystem path
$client->unicodeAlt = true; // keep the unicode char in alt=""
$client->ascii = false; // don't emit :) style fallbacks
return $client;
});
(Property names have shifted across major versions — verify against the Client class you actually installed.)
First use case: rendering user-generated content (comments, chat, bios) as a consistent emoji set instead of relying on the visitor's OS:
$html = app(Client::class)->toImage(e($comment->body));
Store shortnames, render images. The most robust pattern for anything that gets searched, indexed, or exported: normalize emoji to :shortname: on write, convert back on read. Unicode emoji are multi-codepoint, break LIKE queries, and change appearance per platform.
// saving
$model->body_short = $client->toShort($request->input('body'));
// rendering
echo $client->shortnameToImage(e($model->body_short));
Blade directive + helper. Wrap the singleton so views stay readable:
Blade::directive('emoji', fn ($expr) => "<?php echo app(\JoyPixels\Client::class)->toImage($expr); ?>");
<div class="prose">@emoji($comment->body_short)</div>
Sanitize first, convert second. toImage() emits <img> tags — running HTMLPurifier (or strip_tags) afterward will strip them, and running it before is required so you never introduce attributes Purifier didn't vet. Keep conversion as the last step before output.
Attribute accessors / casts. Centralize conversion on the model so controllers and API resources don't each reach for the client:
public function getBodyHtmlAttribute(): string
{
return app(Client::class)->shortnameToImage(e($this->body_short));
}
API responses. Return emoji as shortnames (:rocket:) in JSON. It's stable, diffable in tests, and keeps payloads small. Let the client render — or ship the JS toolkit on the frontend and keep its imagePath config identical to the PHP one.
Mail and notifications. Rendered image URLs must be absolute and web-reachable from an email client. Set imagePathSVG to config('app.url').'/emoji/' in the mail context (a separate client binding, or override per-call), otherwise recipients get broken images.
Cache rendered output. Conversion is regex-heavy and runs per request. Cache the final HTML per comment/article (Cache::remember("comment.html.{$id}", ...)) and bust it when the emoji toolkit version or config changes.
Keep the frontend/backend sets in sync. If you use the JS toolkit in the browser and the PHP port on the server, pin both to the same version — otherwise the same shortname renders as different artwork in a live preview vs. after save.
NOASSERTION means you must actually read the license. JoyPixels' free tier requires visible attribution and restricts redistribution and some commercial uses; a paid license is needed for many production scenarios. Get this signed off before it becomes load-bearing.$client->sprites = true with the sprite CSS) rather than dumping 3,000+ files into public/. Consider serving from a CDN and pointing imagePath* at it.imagePathSVG / imagePathPNG are URL prefixes, not filesystem paths. Setting them to storage_path(...) produces silently broken images. Files must be reachable over HTTP.toImage() twice on already-converted HTML mangles the output (it will try to match inside alt attributes). Convert exactly once, at the edge.htmlspecialchars() after toImage().utf8mb4 (not utf8) and the connection charset too — otherwise you get Incorrect string value or silent ? truncation. Watch index length on utf8mb4 columns in older MySQL.unifyUnicode / unifyHTML behavior if you're normalizing input.ascii = true turns :) into an emoji — fine for display, never for round-tripping stored content.composer require joypixels/emoji-toolkit:1.x.y rather than ^1.0, and assert on shortnames in tests, not on <img src="..."> markup, which churns every release.JoyPixels\Client if you need custom paths per context (web vs. email), and keep your own config file (config/emoji.php) as the single source of truth for size, type, and asset host — the package itself won't give you one.How can I help you explore Laravel packages today?