Fix mobile AI chat keyboard overlap and keep input focused

This commit is contained in:
2026-02-23 13:05:42 +01:00
parent 273859902d
commit 7696b6b298
2 changed files with 35 additions and 7 deletions

View File

@@ -76,7 +76,9 @@
const messages = chatRoot.querySelector(".ai-chat__messages"); const messages = chatRoot.querySelector(".ai-chat__messages");
const form = chatRoot.querySelector(".ai-chat__form"); const form = chatRoot.querySelector(".ai-chat__form");
const input = chatRoot.querySelector(".ai-chat__input"); const input = chatRoot.querySelector(".ai-chat__input");
const sendBtn = chatRoot.querySelector(".ai-chat__send");
const backToTop = document.getElementById("back-to-top"); const backToTop = document.getElementById("back-to-top");
const viewport = window.visualViewport;
function addMessage(text, fromUser) { function addMessage(text, fromUser) {
const bubble = document.createElement("p"); const bubble = document.createElement("p");
@@ -96,12 +98,14 @@
addMessage(introMessage, false); addMessage(introMessage, false);
} }
input.focus(); input.focus();
syncKeyboardOffset();
} }
function closeChat() { function closeChat() {
panel.classList.remove("is-open"); panel.classList.remove("is-open");
panel.setAttribute("aria-hidden", "true"); panel.setAttribute("aria-hidden", "true");
fab.setAttribute("aria-expanded", "false"); fab.setAttribute("aria-expanded", "false");
syncKeyboardOffset();
} }
function randomItem(items) { function randomItem(items) {
@@ -123,6 +127,18 @@
); );
} }
function syncKeyboardOffset() {
if (!viewport) {
chatRoot.style.setProperty("--ai-chat-keyboard-offset", "0px");
return;
}
const offset = Math.max(
0,
Math.round(window.innerHeight - viewport.height - viewport.offsetTop),
);
chatRoot.style.setProperty("--ai-chat-keyboard-offset", `${offset}px`);
}
fab.addEventListener("click", () => { fab.addEventListener("click", () => {
if (panel.classList.contains("is-open")) { if (panel.classList.contains("is-open")) {
closeChat(); closeChat();
@@ -132,6 +148,10 @@
}); });
closeBtn.addEventListener("click", closeChat); closeBtn.addEventListener("click", closeChat);
sendBtn.addEventListener("pointerdown", (event) => {
// Keep focus on the input so mobile keyboards stay open after sending.
event.preventDefault();
});
form.addEventListener("submit", (event) => { form.addEventListener("submit", (event) => {
event.preventDefault(); event.preventDefault();
@@ -142,6 +162,7 @@
addMessage(text, true); addMessage(text, true);
addMessage(buildReply(), false); addMessage(buildReply(), false);
input.value = ""; input.value = "";
input.focus({ preventScroll: true });
}); });
if (backToTop) { if (backToTop) {
@@ -152,5 +173,11 @@
}); });
window.addEventListener("resize", syncChatPosition); window.addEventListener("resize", syncChatPosition);
} }
if (viewport) {
viewport.addEventListener("resize", syncKeyboardOffset);
viewport.addEventListener("scroll", syncKeyboardOffset);
}
window.addEventListener("resize", syncKeyboardOffset);
syncChatPosition(); syncChatPosition();
syncKeyboardOffset();
})(); })();

View File

@@ -881,7 +881,7 @@ li a span {
.ai-chat { .ai-chat {
position: fixed; position: fixed;
right: 24px; right: 24px;
bottom: 24px; bottom: calc(24px + var(--ai-chat-keyboard-offset, 0px));
z-index: 1100; z-index: 1100;
transition: bottom 0.25s ease; transition: bottom 0.25s ease;
font-family: font-family:
@@ -896,7 +896,7 @@ li a span {
} }
.ai-chat.ai-chat--raised { .ai-chat.ai-chat--raised {
bottom: 96px; bottom: calc(96px + var(--ai-chat-keyboard-offset, 0px));
} }
.ai-chat__fab { .ai-chat__fab {
@@ -1012,21 +1012,22 @@ li a span {
@media (max-width: 600px) { @media (max-width: 600px) {
.ai-chat { .ai-chat {
right: 14px; right: 14px;
bottom: 14px; bottom: calc(14px + var(--ai-chat-keyboard-offset, 0px));
} }
.ai-chat.ai-chat--raised { .ai-chat.ai-chat--raised {
bottom: 82px; bottom: calc(82px + var(--ai-chat-keyboard-offset, 0px));
} }
.ai-chat__panel { .ai-chat__panel {
position: fixed; position: fixed;
inset: 0; top: 0;
right: 0;
left: 0;
bottom: var(--ai-chat-keyboard-offset, 0px);
width: 100vw; width: 100vw;
max-width: none; max-width: none;
border-radius: 0; border-radius: 0;
bottom: 0;
right: 0;
} }
.ai-chat__panel.is-open { .ai-chat__panel.is-open {