Skip to content
← Typing Indicator
Edit Typing Indicator
Name
Also known as (comma separated)
Brief definition
Shows that another user is typing.
Notes
Tier
Core
Useful
Reference
Deleted
Controls schema (JSON array)
[ { "id": "names", "type": "text", "label": "Name(s) typing", "default": "Priya" }, { "id": "count", "type": "select", "label": "People typing", "default": "1", "options": [ "1", "2", "3plus" ] }, { "id": "dotColor", "type": "color", "label": "Dot colour", "default": "#241430", "presets": [ "#241430", "#A8E6C1", "#F5C2E0", "#BFD9F2", "#D9C8F0" ] }, { "id": "showAvatar", "type": "toggle", "label": "Show avatar shape", "default": true }, { "id": "speed", "type": "number", "label": "Animation speed (ms)", "default": 900, "min": 400, "max": 2000, "step": 100 } ]
Templates (JSON object keyed by format)
{ "html": "<div class=\"typing\" role=\"status\" aria-live=\"polite\" data-count=\"{{count}}\" style=\"--speed:{{speed}}ms;--dot:{{dotColor}};\">\n {{#if showAvatar}}<span class=\"typing__avatar\" aria-hidden=\"true\"></span>{{/if}}\n <span class=\"typing__text typing__text--c1\">{{names}} is typing…</span>\n <span class=\"typing__text typing__text--c2\">{{names}} and another person are typing…</span>\n <span class=\"typing__text typing__text--c3plus\">Several people are typing…</span>\n <span class=\"typing__dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span>\n</div>\n<style>\n.typing { display: inline-flex; align-items: center; gap: 8px; font: 13px system-ui, sans-serif; color: #24143099; background: #FAF7F2; border: 1px solid #24143020; border-radius: 999px; padding: 6px 12px; }\n.typing__avatar { width: 20px; height: 20px; border-radius: 50%; background: #24143014; flex-shrink: 0; }\n.typing__text { display: none; }\n[data-count=\"1\"] .typing__text--c1 { display: inline; }\n[data-count=\"2\"] .typing__text--c2 { display: inline; }\n[data-count=\"3plus\"] .typing__text--c3plus { display: inline; }\n.typing__dots { display: inline-flex; gap: 3px; }\n.typing__dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--dot); display: inline-block; }\n@keyframes typing-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-3px); opacity: 1; } }\n@media (prefers-reduced-motion: no-preference) {\n .typing__dots i { animation: typing-bounce var(--speed) ease-in-out infinite; }\n .typing__dots i:nth-child(2) { animation-delay: calc(var(--speed) / 6); }\n .typing__dots i:nth-child(3) { animation-delay: calc(var(--speed) / 3); }\n}\n</style>", "tailwind": "<div role=\"status\" aria-live=\"polite\" class=\"typing-tw inline-flex items-center gap-2 text-[13px] text-[#24143099] bg-[#FAF7F2] border border-[#24143020] rounded-full px-3 py-1.5\" data-count=\"{{count}}\" style=\"--speed:{{speed}}ms;--dot:{{dotColor}}\">\n {{#if showAvatar}}<span aria-hidden=\"true\" class=\"w-5 h-5 rounded-full bg-[#24143014] flex-shrink-0\"></span>{{/if}}\n <span class=\"typing-tw__text typing-tw__text--c1\">{{names}} is typing…</span>\n <span class=\"typing-tw__text typing-tw__text--c2\">{{names}} and another person are typing…</span>\n <span class=\"typing-tw__text typing-tw__text--c3plus\">Several people are typing…</span>\n <span aria-hidden=\"true\" class=\"typing-tw__dots inline-flex gap-[3px]\"><i></i><i></i><i></i></span>\n</div>\n<style>\n.typing-tw__text { display: none; }\n[data-count=\"1\"] .typing-tw__text--c1 { display: inline; }\n[data-count=\"2\"] .typing-tw__text--c2 { display: inline; }\n[data-count=\"3plus\"] .typing-tw__text--c3plus { display: inline; }\n.typing-tw__dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--dot); display: inline-block; }\n@keyframes typing-tw-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-3px); opacity: 1; } }\n@media (prefers-reduced-motion: no-preference) {\n .typing-tw__dots i { animation: typing-tw-bounce var(--speed) ease-in-out infinite; }\n .typing-tw__dots i:nth-child(2) { animation-delay: calc(var(--speed) / 6); }\n .typing-tw__dots i:nth-child(3) { animation-delay: calc(var(--speed) / 3); }\n}\n</style>", "react": "export function TypingIndicator({\n names = \"{{names}}\",\n count = \"{{count}}\",\n dotColor = \"{{dotColor}}\",\n showAvatar = {{showAvatar}},\n speed = {{speed}},\n}) {\n const text = {\n \"1\": `${names} is typing…`,\n \"2\": `${names} and another person are typing…`,\n \"3plus\": \"Several people are typing…\",\n }[count];\n return (\n <div role=\"status\" aria-live=\"polite\" style={{ display: \"inline-flex\", alignItems: \"center\", gap: 8, fontSize: 13,\n color: \"#24143099\", background: \"#FAF7F2\", border: \"1px solid #24143020\", borderRadius: 999, padding: \"6px 12px\" }}>\n {showAvatar && <span aria-hidden=\"true\" style={{ width: 20, height: 20, borderRadius: \"50%\", background: \"#24143014\", flexShrink: 0 }} />}\n <span>{text}</span>\n <span aria-hidden=\"true\" style={{ display: \"inline-flex\", gap: 3 }}>\n {[0, 1, 2].map((i) => (\n <i key={i} className=\"typing-dot\" style={{ width: 5, height: 5, borderRadius: \"50%\", background: dotColor, display: \"inline-block\",\n \"--typing-delay\": `${(speed / 6) * i}ms` }} />\n ))}\n </span>\n <style>{`\n @media (prefers-reduced-motion: no-preference) {\n .typing-dot { animation: typing-react-bounce ${speed}ms ease-in-out infinite; animation-delay: var(--typing-delay); }\n @keyframes typing-react-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-3px); opacity: 1; } }\n }\n `}</style>\n </div>\n );\n}" }
Save
History