Skip to content
← Message Composer
Edit Message Composer
Name
Also known as (comma separated)
Brief definition
Interface for composing a message.
Notes
Tier
Core
Useful
Reference
Deleted
Controls schema (JSON array)
[ { "id": "placeholder", "type": "text", "label": "Placeholder", "default": "Write a message…" }, { "id": "draft", "type": "text", "label": "Draft text", "default": "Let's ship the update on Friday." }, { "id": "variant", "type": "select", "label": "Variant", "default": "expanded", "options": [ "compact", "expanded", "threaded" ] }, { "id": "attachEnabled", "type": "toggle", "label": "Show attach button", "default": true }, { "id": "charLimit", "type": "number", "label": "Character limit", "default": 280, "min": 50, "max": 1000, "step": 10 } ]
Templates (JSON object keyed by format)
{ "html": "<form class=\"composer composer--{{variant}}\" data-variant=\"{{variant}}\">\n <label class=\"composer__label\" for=\"composer-input\">Message</label>\n <textarea id=\"composer-input\" class=\"composer__input\" placeholder=\"{{placeholder}}\" rows=\"3\">{{draft}}</textarea>\n <div class=\"composer__toolbar\">\n {{#if attachEnabled}}\n <button type=\"button\" class=\"composer__icon-btn\" aria-label=\"Attach file\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M7 12v6a3 3 0 0 0 6 0V8a5 5 0 0 0-10 0v9a7 7 0 0 0 14 0V10\"/></svg>\n </button>\n {{/if}}\n <span class=\"composer__count\">{{charLimit}} character limit</span>\n <button type=\"button\" class=\"composer__send\">Send</button>\n </div>\n</form>\n<style>\n.composer { font: 14px/1.5 system-ui, sans-serif; max-width: 420px; box-sizing: border-box; background: #FAF7F2; color: #241430; border: 1px solid #24143026; border-radius: 12px; padding: 16px; }\n.composer--compact { padding: 8px; border-radius: 8px; }\n.composer--expanded { padding: 20px; }\n.composer--threaded { padding: 16px 16px 16px 13px; border-left: 3px solid #A8E6C1; border-radius: 4px 12px 12px 4px; }\n.composer__label { display: block; font-weight: 600; margin-bottom: 6px; font-size: 13px; }\n.composer__input { width: 100%; box-sizing: border-box; font: inherit; border: 1px solid #24143033; border-radius: 8px; padding: 10px; resize: vertical; background: #ffffff; color: #241430; }\n.composer__input:focus-visible { outline: 2px solid #241430; outline-offset: 1px; }\n.composer__toolbar { display: flex; align-items: center; gap: 10px; margin-top: 10px; }\n.composer__icon-btn { border: none; background: transparent; color: #241430; cursor: pointer; padding: 6px; border-radius: 6px; display: inline-flex; }\n.composer__icon-btn:hover { background: #24143014; }\n.composer__icon-btn:focus-visible { outline: 2px solid #241430; outline-offset: 1px; }\n.composer__count { font-size: 12px; color: #24143099; flex: 1; }\n.composer__send { margin-left: auto; background: #241430; color: #FAF7F2; border: none; border-radius: 8px; padding: 8px 16px; font: 600 13px system-ui, sans-serif; cursor: pointer; }\n.composer__send:hover { opacity: .9; }\n.composer__send:focus-visible { outline: 2px solid #A8E6C1; outline-offset: 2px; }\n</style>", "tailwind": "<form class=\"composer-tw composer-tw--{{variant}} max-w-[420px] box-border bg-[#FAF7F2] text-[#241430] border border-[#24143026] rounded-xl p-4\" data-variant=\"{{variant}}\">\n <label class=\"block font-semibold mb-1.5 text-[13px]\" for=\"composer-tw-input\">Message</label>\n <textarea id=\"composer-tw-input\" rows=\"3\" placeholder=\"{{placeholder}}\" class=\"w-full box-border font-sans border border-[#24143033] rounded-lg p-2.5 bg-white text-[#241430] resize-y\">{{draft}}</textarea>\n <div class=\"flex items-center gap-2.5 mt-2.5\">\n {{#if attachEnabled}}\n <button type=\"button\" aria-label=\"Attach file\" class=\"border-0 bg-transparent text-[#241430] cursor-pointer p-1.5 rounded-md inline-flex hover:bg-[#24143014]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M7 12v6a3 3 0 0 0 6 0V8a5 5 0 0 0-10 0v9a7 7 0 0 0 14 0V10\"/></svg>\n </button>\n {{/if}}\n <span class=\"text-xs text-[#24143099] flex-1\">{{charLimit}} character limit</span>\n <button type=\"button\" class=\"ml-auto bg-[#241430] text-[#FAF7F2] border-0 rounded-lg px-4 py-2 text-[13px] font-semibold cursor-pointer\">Send</button>\n </div>\n</form>\n<style>\n.composer-tw--compact { padding: 8px !important; border-radius: 8px !important; }\n.composer-tw--expanded { padding: 20px !important; }\n.composer-tw--threaded { padding: 16px 16px 16px 13px !important; border-left: 3px solid #A8E6C1 !important; border-radius: 4px 12px 12px 4px !important; }\n</style>", "react": "export function MessageComposer({\n placeholder = \"{{placeholder}}\",\n draft = \"{{draft}}\",\n variant = \"{{variant}}\",\n attachEnabled = {{attachEnabled}},\n charLimit = {{charLimit}},\n}) {\n const pad = { compact: 8, expanded: 20, threaded: 16 }[variant] ?? 16;\n const border = variant === \"threaded\" ? \"3px solid #A8E6C1\" : \"1px solid #24143026\";\n return (\n <form style={{ font: \"14px/1.5 system-ui, sans-serif\", maxWidth: 420, boxSizing: \"border-box\",\n background: \"#FAF7F2\", color: \"#241430\", borderRadius: 12, padding: pad,\n borderLeft: variant === \"threaded\" ? border : undefined,\n border: variant === \"threaded\" ? undefined : border }}>\n <label htmlFor=\"mc-input\" style={{ display: \"block\", fontWeight: 600, marginBottom: 6, fontSize: 13 }}>Message</label>\n <textarea id=\"mc-input\" rows={3} placeholder={placeholder} defaultValue={draft}\n style={{ width: \"100%\", boxSizing: \"border-box\", font: \"inherit\", border: \"1px solid #24143033\",\n borderRadius: 8, padding: 10, background: \"#fff\", color: \"#241430\" }} />\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, marginTop: 10 }}>\n {attachEnabled && (\n <button type=\"button\" aria-label=\"Attach file\" style={{ border: \"none\", background: \"transparent\", color: \"#241430\", cursor: \"pointer\", padding: 6, borderRadius: 6, display: \"inline-flex\" }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden=\"true\"><path d=\"M7 12v6a3 3 0 0 0 6 0V8a5 5 0 0 0-10 0v9a7 7 0 0 0 14 0V10\" /></svg>\n </button>\n )}\n <span style={{ fontSize: 12, color: \"#24143099\", flex: 1 }}>{charLimit} character limit</span>\n <button type=\"button\" style={{ marginLeft: \"auto\", background: \"#241430\", color: \"#FAF7F2\", border: \"none\", borderRadius: 8, padding: \"8px 16px\", fontSize: 13, fontWeight: 600, cursor: \"pointer\" }}>Send</button>\n </div>\n </form>\n );\n}" }
Save
History