By Sagar Shankaran, Founder of CallSphere
Design and build a mobile-first AI agent chat interface with responsive layouts, proper touch targets, virtual keyboard handling, and progressive web app patterns.
Key takeaways
Over 60% of web traffic comes from mobile devices, yet most AI chat interfaces are designed desktop-first and merely shrink on smaller screens. A mobile-first approach means designing for the smallest screen first and progressively enhancing for larger viewports. This results in an interface that works well everywhere instead of one that is awkward on phones.
The fundamental challenge on mobile is the virtual keyboard. When the keyboard opens, it reduces the visible viewport by 40-50%. The chat input must remain visible above the keyboard, and the message list must not jump unexpectedly.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
function MobileChat() {
return (
<div
className="flex flex-col"
style={{ height: "100dvh" }}
>
<ChatHeader />
<MessageList className="flex-1 overflow-y-auto" />
<ChatInput />
</div>
);
}
The 100dvh unit (dynamic viewport height) is critical. Unlike 100vh which uses the full viewport including the area behind the virtual keyboard, 100dvh adjusts when the keyboard opens. This prevents the input from being pushed off-screen.
Apple's Human Interface Guidelines recommend a minimum touch target of 44x44 points. Google's Material Design uses 48x48 dp. Anything smaller frustrates users who have to tap multiple times to hit a tiny button.
function ActionButton({
icon,
label,
onClick,
}: {
icon: React.ReactNode;
label: string;
onClick: () => void;
}) {
return (
<button
onClick={onClick}
className="min-w-[44px] min-h-[44px] flex items-center
justify-center rounded-xl active:bg-gray-100
transition-colors"
aria-label={label}
>
{icon}
</button>
);
}
The active:bg-gray-100 class provides immediate visual feedback on tap. The transition-colors makes the state change feel smooth rather than abrupt.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
When the virtual keyboard appears, the visualViewport API lets you detect the available space and adjust the layout accordingly.
import { useEffect, useState } from "react";
function useKeyboardHeight() {
const [keyboardHeight, setKeyboardHeight] = useState(0);
useEffect(() => {
const viewport = window.visualViewport;
if (!viewport) return;
const handleResize = () => {
const heightDiff = window.innerHeight - viewport.height;
setKeyboardHeight(Math.max(0, heightDiff));
};
viewport.addEventListener("resize", handleResize);
return () =>
viewport.removeEventListener("resize", handleResize);
}, []);
return keyboardHeight;
}
Use this hook to add bottom padding to the chat container when the keyboard is open, ensuring the latest messages and the input field remain visible.
On mobile, message bubbles should use more of the available width. On desktop, they should be narrower to maintain readability.
function ResponsiveBubble({
message,
}: {
message: { role: string; content: string };
}) {
const isUser = message.role === "user";
return (
<div className={`flex ${isUser ? "justify-end" : "justify-start"}
px-3 mb-2`}>
<div
className={`rounded-2xl px-3.5 py-2.5 text-sm
max-w-[85%] sm:max-w-[75%] md:max-w-[65%]
${isUser
? "bg-blue-600 text-white"
: "bg-gray-100 text-gray-900"
}`}
>
{message.content}
</div>
</div>
);
}
The max-w-[85%] on mobile gives bubbles more room. On sm screens and up, the width decreases to maintain comfortable line lengths.
Mobile users expect gesture-based interactions. Implement a swipe gesture for reply-to-message functionality.
import { useRef } from "react";
function useSwipeGesture(onSwipeRight: () => void) {
const startX = useRef(0);
const onTouchStart = (e: React.TouchEvent) => {
startX.current = e.touches[0].clientX;
};
const onTouchEnd = (e: React.TouchEvent) => {
const endX = e.changedTouches[0].clientX;
const diff = endX - startX.current;
if (diff > 80) {
onSwipeRight();
}
};
return { onTouchStart, onTouchEnd };
}
A threshold of 80 pixels distinguishes intentional swipes from accidental touches. Keep the gesture detection simple and only support the most common directions to avoid conflicts with browser navigation gestures.
Adding a PWA manifest allows users to install the agent chat on their home screen for a native-like experience.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
// next.config.mjs or manual manifest
const manifest = {
name: "AI Agent Chat",
short_name: "Agent",
start_url: "/chat",
display: "standalone",
background_color: "#ffffff",
theme_color: "#2563eb",
icons: [
{ src: "/icon-192.png", sizes: "192x192", type: "image/png" },
{ src: "/icon-512.png", sizes: "512x512", type: "image/png" },
],
};
The display: "standalone" removes the browser chrome, making the chat feel like a native app. Combined with a service worker for offline support, this creates a compelling mobile experience.
Disable zoom on the input field to prevent iOS from zooming in when the font size is below 16px.
function MobileInput() {
return (
<textarea
className="text-base w-full rounded-xl border px-4 py-3"
style={{ fontSize: "16px" }}
placeholder="Message..."
/>
);
}
Setting the font size to 16px or larger prevents iOS Safari from auto-zooming. This is one of the most common mobile UI bugs in chat interfaces.
Use the env(safe-area-inset-bottom) CSS variable to add padding below the chat input. In Tailwind, use the pb-safe utility (requires the tailwindcss-safe-area plugin) or set the padding manually with style={{ paddingBottom: "env(safe-area-inset-bottom)" }}.
For a chat interface, a well-built PWA provides 90% of the native experience with zero app store overhead. Use a native wrapper only if you need push notifications on iOS (which requires a native app until Web Push is fully supported) or direct access to hardware APIs like Bluetooth or NFC.
Use Chrome DevTools device emulation for quick iteration, but always test on real devices. The virtual keyboard behavior, safe areas, and touch responsiveness differ significantly between the emulator and actual iPhones and Android devices. Use BrowserStack or a physical device lab for final validation.
#Mobile #ResponsiveDesign #PWA #TouchUI #AIAgentInterface #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
Mobile WebRTC has matured past hardware-AEC quirks and battery cliffs. Here is the 2026 mobile playbook for shipping voice-AI agents that survive 30-minute calls.
On-device AI plus WebRTC plus a 5G modem is a thermal worst case. Here is the 2026 playbook for keeping AI voice agent calls below the throttling cliff.
Apple's background audio mode is the only sanctioned path to keep recording when the user locks the iPhone. Here is the 2026 playbook for AI dictation apps.
Android's AudioRecord API is the lowest-level mic access for AI voice apps. Here is how to configure it for 16 kHz PCM, hardware AEC, and sub-300 ms streaming.
ICE restart is how an AI voice call survives Wi-Fi to cellular handoff without dropping the conversation. Here is the 2026 production pattern that keeps the agent alive.
Expo Go cannot run WebRTC. EAS Dev Client can. Here is the 2026 config-plugin recipe for shipping AI voice agents on Expo without abandoning the managed workflow.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI