Inline Shortcut Typer
A text shortcut demo inside an email editor: type a semicolon plus a shortcut name, a replacement hint pops up and expands into a full paragraph. Tabs on top switch between thanks, signature and meeting shortcuts; the typing loops, or click to trigger it yourself.
Taken from the page template Suitie Mac Clipboard History Website. Use it on its own, or combine it with the other components from the same template to rebuild the full page.
Plain HTML, CSS and a little vanilla JS, with no framework dependency. Copy the prompt into Claude Code, Cursor, Trae or Codex and the model adds Inline Shortcut Typer to your project in your colors.
Where to use it
Search boxes, AI chat inputs, form fields, file uploads, verification codes and anywhere else people type.
Install
With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.
Code
Source for Inline Shortcut Typer. Motion uses only transform and opacity and respects the Reduce motion setting.
<div class="x-ils"><div class="x-ils__keys"><span class="x-ils__k is-on">;谢谢</span><span class="x-ils__k">;签名</span><span class="x-ils__k">;会议</span><span class="x-ils__k x-ils__k--add"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg></span></div><div class="x-ils__win"><div class="x-ils__bar"><span class="x-ils__dots"><i></i><i></i><i></i></span><b>新邮件</b></div><div class="x-ils__row"><span>收件人</span>name@example.com</div><div class="x-ils__row"><span>主题</span>关于合作的回复</div><div class="x-ils__body"><span class="x-ils__pre">你好,</span><br><span class="x-ils__out"></span><span class="x-ils__typed"></span><i class="x-ils__caret"></i></div><div class="x-ils__pop"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="12" rx="2.5"/><path d="M7 10h.01M10.5 10h.01M14 10h.01M17 10h.01M7 14h10"/></svg><span>随贴将替换为</span><b class="x-ils__preview"></b></div></div></div>
.x-ils{box-sizing:border-box;width:100%;max-width:820px;margin:0 auto;padding:28px;border-radius:30px;background:linear-gradient(180deg,#eef4ff,#f6f7fb);color:#0b0b0f;font-family:"PingFang SC","Noto Sans SC","Noto Sans CJK SC","Microsoft YaHei",system-ui,sans-serif;-webkit-font-smoothing:antialiased}.x-ils *,.x-ils *::before,.x-ils *::after{box-sizing:border-box}.x-ils svg{width:1em;height:1em;flex:none}.x-ils__keys{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:18px}.x-ils__k{display:inline-flex;align-items:center;height:34px;padding:0 14px;border-radius:10px;background:#fff;font:600 13px ui-monospace,SFMono-Regular,Menlo,monospace;color:#3a3a42;box-shadow:0 1px 0 rgba(0,0,0,.05),inset 0 -2px 0 rgba(0,0,0,.06)}.x-ils__k.is-on{background:#0b0b0f;color:#fff}.x-ils__k--add{width:34px;justify-content:center;padding:0;font-size:15px}.x-ils__win{position:relative;border-radius:18px;background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.06),0 30px 60px -30px rgba(20,40,90,.35)}.x-ils__bar{display:flex;align-items:center;gap:14px;height:44px;padding:0 16px;border-bottom:1px solid #efeff2;font-size:13px}.x-ils__dots{display:flex;gap:7px}.x-ils__dots i{width:11px;height:11px;border-radius:50%;background:#ff5f57}.x-ils__dots i:nth-child(2){background:#febc2e}.x-ils__dots i:nth-child(3){background:#28c840}.x-ils__row{display:flex;gap:12px;padding:12px 20px;border-bottom:1px solid #f2f2f5;font-size:14px;color:#3a3a42}.x-ils__row span{width:48px;color:#9a9aa3}.x-ils__body{min-height:150px;padding:18px 20px 24px;font-size:16px;line-height:1.8}.x-ils__out{background:linear-gradient(90deg,rgba(61,123,255,.18),rgba(61,123,255,0));border-radius:4px;transition:background 1.2s}.x-ils__out.is-settle{background:transparent}.x-ils__typed{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:#3d7bff}.x-ils__caret{display:inline-block;width:2px;height:20px;margin-left:1px;vertical-align:-4px;background:#0b0b0f;animation:x-ils-blink 1s steps(1) infinite}@keyframes x-ils-blink{50%{opacity:0}}.x-ils__pop{position:absolute;left:20px;bottom:-22px;display:flex;align-items:center;gap:8px;max-width:calc(100% - 40px);padding:10px 14px;border-radius:14px;background:#0b0b0f;color:#fff;font-size:13px;box-shadow:0 18px 40px -12px rgba(0,0,0,.45);opacity:0;transform:translateY(8px);transition:opacity .25s,transform .3s cubic-bezier(.2,.8,.2,1)}.x-ils__pop span{color:#a1a1aa;white-space:nowrap}.x-ils__pop b{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.x-ils__pop.is-show{opacity:1;transform:none}@media (max-width:560px){.x-ils{padding:16px}.x-ils__body{font-size:15px}}@media (prefers-reduced-motion:reduce){.x-ils__caret{animation:none}.x-ils__pop,.x-ils__out{transition:none}}(root) => {
const typed = root.querySelector('.x-ils__typed');
const out = root.querySelector('.x-ils__out');
const pop = root.querySelector('.x-ils__pop');
const prev = root.querySelector('.x-ils__preview');
const keys = [...root.querySelectorAll('.x-ils__k:not(.x-ils__k--add)')];
const S = [
[';谢谢', '感谢来信!方案已经收到,我们周内整理好意见再回复你。'],
[';签名', '此致,随贴团队 · name@example.com'],
[';会议', '下周二下午可以吗?我先发一个会议邀请过去。']
];
let k = 0, i = 0, t = 0, t2 = 0;
…