Interface for composing a message.
<form class="composer composer--expanded" data-variant="expanded">
<label class="composer__label" for="composer-input">Message</label>
<textarea id="composer-input" class="composer__input" placeholder="Write a message…" rows="3">Let's ship the update on Friday.</textarea>
<div class="composer__toolbar">
<button type="button" class="composer__icon-btn" aria-label="Attach file">
<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>
</button>
<span class="composer__count">280 character limit</span>
<button type="button" class="composer__send">Send</button>
</div>
</form>
<style>
.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; }
.composer--compact { padding: 8px; border-radius: 8px; }
.composer--expanded { padding: 20px; }
.composer--threaded { padding: 16px 16px 16px 13px; border-left: 3px solid #A8E6C1; border-radius: 4px 12px 12px 4px; }
.composer__label { display: block; font-weight: 600; margin-bottom: 6px; font-size: 13px; }
.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; }
.composer__input:focus-visible { outline: 2px solid #241430; outline-offset: 1px; }
.composer__toolbar { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.composer__icon-btn { border: none; background: transparent; color: #241430; cursor: pointer; padding: 6px; border-radius: 6px; display: inline-flex; }
.composer__icon-btn:hover { background: #24143014; }
.composer__icon-btn:focus-visible { outline: 2px solid #241430; outline-offset: 1px; }
.composer__count { font-size: 12px; color: #24143099; flex: 1; }
.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; }
.composer__send:hover { opacity: .9; }
.composer__send:focus-visible { outline: 2px solid #A8E6C1; outline-offset: 2px; }
</style><form class="composer-tw composer-tw--expanded max-w-[420px] box-border bg-[#FAF7F2] text-[#241430] border border-[#24143026] rounded-xl p-4" data-variant="expanded">
<label class="block font-semibold mb-1.5 text-[13px]" for="composer-tw-input">Message</label>
<textarea id="composer-tw-input" rows="3" placeholder="Write a message…" class="w-full box-border font-sans border border-[#24143033] rounded-lg p-2.5 bg-white text-[#241430] resize-y">Let's ship the update on Friday.</textarea>
<div class="flex items-center gap-2.5 mt-2.5">
<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]">
<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>
</button>
<span class="text-xs text-[#24143099] flex-1">280 character limit</span>
<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>
</div>
</form>
<style>
.composer-tw--compact { padding: 8px !important; border-radius: 8px !important; }
.composer-tw--expanded { padding: 20px !important; }
.composer-tw--threaded { padding: 16px 16px 16px 13px !important; border-left: 3px solid #A8E6C1 !important; border-radius: 4px 12px 12px 4px !important; }
</style>export function MessageComposer({
placeholder = "Write a message…",
draft = "Let's ship the update on Friday.",
variant = "expanded",
attachEnabled = true,
charLimit = 280,
}) {
const pad = { compact: 8, expanded: 20, threaded: 16 }[variant] ?? 16;
const border = variant === "threaded" ? "3px solid #A8E6C1" : "1px solid #24143026";
return (
<form style={{ font: "14px/1.5 system-ui, sans-serif", maxWidth: 420, boxSizing: "border-box",
background: "#FAF7F2", color: "#241430", borderRadius: 12, padding: pad,
borderLeft: variant === "threaded" ? border : undefined,
border: variant === "threaded" ? undefined : border }}>
<label htmlFor="mc-input" style={{ display: "block", fontWeight: 600, marginBottom: 6, fontSize: 13 }}>Message</label>
<textarea id="mc-input" rows={3} placeholder={placeholder} defaultValue={draft}
style={{ width: "100%", boxSizing: "border-box", font: "inherit", border: "1px solid #24143033",
borderRadius: 8, padding: 10, background: "#fff", color: "#241430" }} />
<div style={{ display: "flex", alignItems: "center", gap: 10, marginTop: 10 }}>
{attachEnabled && (
<button type="button" aria-label="Attach file" style={{ border: "none", background: "transparent", color: "#241430", cursor: "pointer", padding: 6, borderRadius: 6, display: "inline-flex" }}>
<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>
</button>
)}
<span style={{ fontSize: 12, color: "#24143099", flex: 1 }}>{charLimit} character limit</span>
<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>
</div>
</form>
);
}