Reply Composer
An inline reply composer that folds out of a comment, in the style of threaded discussion UIs. When transitionfinish fires, the textarea grabs focus if the composer is open and is cleared if it is closed, once the text is out of sight. That way Cancel and a sent reply both leave a clean composer behind. The event does not bubble, so the listener sits on the collapsible itself. Swap the send button's close() call for your actual submit logic.
Code
The following example assumes that you have imported the component and set up the theme.
<div class="comment">23 collapsed lines
<span class="avatar" aria-hidden="true">MK</span>
<div class="body"> <p class="meta"> <strong>Maya K.</strong> <span>2 hours ago</span> </p>
<p class="text">Shipping the docs rewrite tomorrow. Anything still missing from the migration guide?</p>
<sv-collapsible class="composer"> <button type="button" class="reply-trigger" slot="trigger">Reply</button>
<div class="editor"> <textarea aria-label="Your reply" placeholder="Write a reply" rows="3"></textarea>
<div class="actions"> <button type="button" class="cancel">Cancel</button> <button type="button" class="send">Reply</button> </div> </div> </sv-collapsible> </div></div>
<script type="application/x-typescript" module>18 collapsed lines
const composer = document.querySelector<Collapsible>(".composer")!; const textarea = composer.querySelector("textarea")!;
composer.addEventListener("transitionfinish", () => { if (composer.opened) { textarea.focus(); } else { textarea.value = ""; } });
composer.querySelector(".cancel")?.addEventListener("click", () => { composer.close(); });
composer.querySelector(".send")?.addEventListener("click", () => { composer.close(); });</script>
<style>109 collapsed lines
.comment { display: flex; gap: 0.75em; inline-size: min(30rem, 100%); padding: 1em; margin-inline: auto; color: var(--sv-gray-2); background: var(--sv-gray-7); border: solid var(--sv-bdr-sz-sm) var(--sv-gray-5); border-radius: var(--sv-bdr-rad-md);
.avatar { display: grid; flex: none; place-items: center; inline-size: 2.25em; block-size: 2.25em; font-size: 0.85em; font-weight: 700; color: var(--sv-accent-content); background: var(--sv-accent); border-radius: 50%; }
.body { flex: 1; min-inline-size: 0; }
.meta { display: flex; gap: 0.5em; align-items: baseline; margin-block: 0;
strong { color: var(--sv-gray-1); }
span { font-size: 0.8em; color: var(--sv-gray-3); } }
.text { margin-block: 0.35em 0.5em; line-height: 1.5; }
.reply-trigger { padding: 0.3em 0; font: inherit; font-size: 0.9em; font-weight: 600; color: var(--sv-accent); cursor: pointer; background: none; border: none; }
.editor { display: grid; gap: 0.5em; padding-block-start: 0.5em;
textarea { padding: 0.55em 0.75em; font: inherit; color: inherit; resize: vertical; background: var(--sv-gray-8); border: solid var(--sv-bdr-sz-sm) var(--sv-gray-5); border-radius: var(--sv-bdr-rad-sm);
&:focus-visible { outline: none; border-color: var(--sv-accent); } }
.actions { display: flex; gap: 0.5em; justify-content: end;
button { padding: 0.45em 0.9em; font: inherit; font-size: 0.9em; font-weight: 600; cursor: pointer; border-radius: var(--sv-bdr-rad-sm); }
.cancel { color: var(--sv-gray-2); background: none; border: solid var(--sv-bdr-sz-sm) var(--sv-gray-5); }
.send { color: var(--sv-accent-content); background: var(--sv-accent); border: none; } } } }</style>
Maya K. 2 hours ago
Shipping the docs rewrite tomorrow. Anything still missing from the migration guide?