Section
AI Chat Interface — Vercel
Refined dark monochrome AI chat surface with hairline borders, a subtle conic glow, a glowing ready-state dot, a streaming typing indicator, prompt chips, and a minimal input bar. Generous spacing and a single teal accent echo a premium dev-tool aesthetic.
- Section
- Tailwind
- HTML
- MIT
Preview
Live section
9:41 100%
devsnips.dev/library/tailwind/sections/ai-product/ai-chat-interface/vercel/ fluid · no fixed width 100%
Install
Add to your project
npx devsnips add Tailwind/Sections/AI-Product/ai-chat-interface/vercel Tailwind/Sections/AI-Product/ai-chat-interface/vercel <!--
Snippet Name: AI Chat Interface — Vercel
Description: Refined dark monochrome chat panel with a subtle conic glow, hairline borders, a streaming reply, prompt suggestions, and a minimal input bar.
Author: DevSnips Contributors
Usage Example: Drop into a dark product shell as an AI assistant surface. Prompt chips and input bar are fully wired in preview.html.
-->
<div class="relative w-full max-w-2xl" data-chat="vc">
<!-- Conic glow backdrop -->
<div class="pointer-events-none absolute -inset-px -z-10 rounded-[14px] opacity-60 [background:radial-gradient(60%_60%_at_50%_0%,rgba(255,255,255,0.10),transparent_70%)]" aria-hidden="true"></div>
<!-- Panel -->
<div class="overflow-hidden rounded-[14px] border border-white/10 bg-[#0a0a0a] shadow-[0_0_0_1px_rgba(255,255,255,0.02),0_20px_60px_-20px_rgba(0,0,0,0.9)]">
<!-- Header -->
<div class="flex items-center justify-between gap-3 border-b border-white/[0.07] px-5 py-4">
<div class="flex items-center gap-3">
<div class="flex h-9 w-9 items-center justify-center rounded-lg border border-white/10 bg-white text-black">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2 2 19h20L12 2z"/></svg>
</div>
<div class="leading-tight">
<p class="font-g text-[13px] font-medium text-white">DevSnips Assistant</p>
<p class="vc-mono mt-0.5 text-[11px] text-white/40">
<span class="vc-dot"></span> Ready · v2
</p>
</div>
</div>
<div class="flex items-center gap-1.5">
<button type="button" class="vc-mono hidden rounded-md px-2.5 py-1.5 text-[11px] text-white/50 transition-colors hover:bg-white/[0.06] hover:text-white sm:block focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">History</button>
<button type="button" aria-label="New chat" class="flex h-8 w-8 items-center justify-center rounded-md text-white/50 transition-colors hover:bg-white/[0.06] hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</button>
</div>
</div>
<!-- Messages -->
<div class="chat-scroll max-h-[440px] min-h-[340px] space-y-6 overflow-y-auto px-5 py-6" data-chat-messages>
<!-- User -->
<div class="flex justify-end">
<div class="max-w-[80%] rounded-2xl rounded-br-md border border-white/10 bg-white/[0.06] px-4 py-2.5">
<p class="vc-mono mb-1 text-[10px] uppercase tracking-wider text-white/35">You</p>
<p class="font-g text-[14px] leading-relaxed text-white/90">How do I animate an accordion with the grid-rows trick?</p>
</div>
</div>
<!-- Assistant -->
<div class="flex justify-start gap-3">
<div class="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border border-white/10 bg-white text-black">
<svg class="h-3 w-3" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2 2 19h20L12 2z"/></svg>
</div>
<div class="max-w-[82%] rounded-2xl rounded-tl-md border border-white/[0.07] bg-transparent px-4 py-2.5">
<p class="vc-mono mb-1 text-[10px] uppercase tracking-wider text-white/35">Assistant</p>
<p class="font-g text-[14px] leading-relaxed text-white/75">
Wrap the panel in <code class="vc-code">grid-rows-[0fr]</code>, animate to <code class="vc-code">grid-rows-[1fr]</code> with <code class="vc-code">transition-[grid-template-rows]</code>, and nest an <code class="vc-code">overflow-hidden</code> wrapper. The row grows from 0 to auto with zero layout cost.
</p>
</div>
</div>
<!-- Typing -->
<div class="flex justify-start gap-3" data-chat-typing>
<div class="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border border-white/10 bg-white text-black">
<svg class="h-3 w-3" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2 2 19h20L12 2z"/></svg>
</div>
<div class="flex items-center gap-1.5 rounded-2xl rounded-tl-md border border-white/[0.07] px-4 py-3">
<span class="vc-typing-dot"></span>
<span class="vc-typing-dot" style="animation-delay:.15s"></span>
<span class="vc-typing-dot" style="animation-delay:.3s"></span>
</div>
</div>
</div>
<!-- Prompt suggestions -->
<div class="flex flex-wrap gap-2 border-t border-white/[0.07] px-5 py-3">
<button type="button" class="chat-prompt vc-mono rounded-full border border-white/10 bg-white/[0.03] px-3 py-1.5 text-[11px] text-white/60 transition-colors hover:border-white/20 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">Explain CSS grid</button>
<button type="button" class="chat-prompt vc-mono rounded-full border border-white/10 bg-white/[0.03] px-3 py-1.5 text-[11px] text-white/60 transition-colors hover:border-white/20 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">Build a toast</button>
<button type="button" class="chat-prompt vc-mono rounded-full border border-white/10 bg-white/[0.03] px-3 py-1.5 text-[11px] text-white/60 transition-colors hover:border-white/20 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-white/30">Refactor my code</button>
</div>
<!-- Input -->
<form class="flex items-center gap-2 border-t border-white/[0.07] px-5 py-4" data-chat-form>
<div class="relative flex-1">
<input
type="text"
name="prompt"
placeholder="Ask anything…"
aria-label="Message DevSnips Assistant"
class="w-full rounded-lg border border-white/10 bg-white/[0.03] px-4 py-2.5 font-g text-[14px] text-white placeholder:text-white/30 focus:border-white/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/20"
/>
</div>
<button type="submit" class="flex shrink-0 items-center gap-2 rounded-lg border border-white/10 bg-white px-4 py-2.5 font-g text-[13px] font-medium text-black transition-colors hover:bg-white/90 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40">
Send
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
</button>
</form>
</div>
<style>
[data-chat="vc"] .vc-mono { font-family: 'Geist Mono', ui-monospace, monospace; }
[data-chat="vc"] .font-g { font-family: 'Geist', sans-serif; }
[data-chat="vc"] .vc-code { font-family: 'Geist Mono', monospace; font-size: 12px; background: rgba(255,255,255,0.06); padding: 1px 5px; border-radius: 4px; color: rgba(255,255,255,0.9); }
[data-chat="vc"] .vc-dot { display: inline-block; height: 6px; width: 6px; border-radius: 9999px; background: #50e3c2; margin-right: 5px; box-shadow: 0 0 8px #50e3c2; vertical-align: middle; }
[data-chat="vc"] .vc-typing-dot { height: 6px; width: 6px; border-radius: 9999px; background: rgba(255,255,255,0.5); animation: vc-bounce 1.2s infinite ease-in-out; }
@keyframes vc-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .4; } 30% { transform: translateY(-4px); opacity: 1; } }
[data-chat="vc"] .chat-scroll::-webkit-scrollbar { width: 6px; }
[data-chat="vc"] .chat-scroll::-webkit-scrollbar-track { background: transparent; }
[data-chat="vc"] .chat-scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 9999px; }
[data-chat="vc"] .chat-scroll { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.15) transparent; }
</style>
<script>
(function () {
var root = document.currentScript.closest('[data-chat="vc"]');
if (!root) return;
var form = root.querySelector('[data-chat-form]');
var list = root.querySelector('[data-chat-messages]');
var input = form && form.querySelector('input[name="prompt"]');
var typing = root.querySelector('[data-chat-typing]');
if (!form || !list || !input) return;
function addUser(text) {
if (!text.trim()) return;
var row = document.createElement('div');
row.className = 'flex justify-end';
row.innerHTML = '<div class="max-w-[80%] rounded-2xl rounded-br-md border border-white/10 bg-white/[0.06] px-4 py-2.5"><p class="vc-mono mb-1 text-[10px] uppercase tracking-wider text-white/35">You</p><p class="font-g text-[14px] leading-relaxed text-white/90"></p></div>';
row.querySelector('p:last-child').textContent = text;
list.appendChild(row);
list.scrollTop = list.scrollHeight;
}
function addBot(text) {
var row = document.createElement('div');
row.className = 'flex justify-start gap-3';
row.innerHTML = '<div class="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border border-white/10 bg-white text-black"><svg class="h-3 w-3" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2 2 19h20L12 2z"/></svg></div><div class="max-w-[82%] rounded-2xl rounded-tl-md border border-white/[0.07] bg-transparent px-4 py-2.5"><p class="vc-mono mb-1 text-[10px] uppercase tracking-wider text-white/35">Assistant</p><p class="font-g text-[14px] leading-relaxed text-white/75"></p></div>';
row.querySelector('p:last-child').textContent = text;
list.appendChild(row);
list.scrollTop = list.scrollHeight;
}
var responses = [
'Use the grid-rows-[0fr] to [1fr] trick wrapped in overflow-hidden for buttery height animation.',
'Try a single-open mode: close sibling items on open and toggle aria-expanded on the trigger.',
'Reach for focus-visible:ring utilities plus role="region" and aria-labelledby for accessibility.',
'Drop the snippet into a docs layout — each item toggles independently with no extra wiring.'
];
var i = 0;
function reply(text) {
addUser(text);
if (typing) { typing.style.display = 'flex'; list.scrollTop = list.scrollHeight; }
setTimeout(function () {
if (typing) typing.style.display = 'none';
addBot(responses[i % responses.length]); i++;
}, 1100);
}
form.addEventListener('submit', function (e) {
e.preventDefault();
reply(input.value);
input.value = '';
});
root.querySelectorAll('.chat-prompt').forEach(function (chip) {
chip.addEventListener('click', function () { reply(chip.textContent.trim()); });
});
})();
</script>
</div> 165 lines UTF-8 · LF · Spaces: 2
Continue browsing