Models 44

Claude Sonnet 5.5

by Anthropicreasoning defaultClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
45.2 s
Cost
$0.079
Output tokens
7,776
Spent thinking
981 tokens
Speed
180.9 tok/s
Console errors
0
First token after
2.2 s
First visible text after
10.4 s
Prompt tokens
745
Code size
15.4 KB
Finish reason
stop
Served by
Claude Platform on AWS
Model id
anthropic/claude-sonnet-5.5
Reasoning sent
model default
Max output
128,000 tokens
Generated
Nov 12, 2026

What it was asked

The prompt
Build an interactive Kanban board in vanilla HTML, CSS and JavaScript (no framework, no library). Requirements: - Three columns: "To do", "In progress", "Done", each showing its card count. - Pre-populate the board with 6 realistic cards spread across the columns so the first screenshot looks alive. - Each card has a title and a priority (low / medium / high) shown as a colored badge. - Add a card through a small modal form (title required), and delete a card with a button on it. - Drag and drop cards between columns with the mouse, with a clear visual drop indicator. - A search field that filters cards live by title. - A light / dark theme toggle. - State lives in memory only (no storage APIs).
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 312 lines

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kanban Board</title>
<style>
  :root{
    --bg:#f3f4f8; --surface:#ffffff; --col:#e8eaf1; --text:#1c2033; --muted:#6b7190;
    --border:#d9dce8; --accent:#5b5bf0; --accent-t:#fff; --shadow:0 1px 2px rgba(20,24,50,.08),0 4px 12px rgba(20,24,50,.06);
    --low-bg:#dcf5e5; --low-fg:#17753d;
    --med-bg:#fff0cc; --med-fg:#8a5a00;
    --high-bg:#ffdcdc; --high-fg:#b3202a;
    --danger:#e5484d;
  }
  [data-theme="dark"]{
    --bg:#0f111a; --surface:#1d2132; --col:#161927; --text:#e9ebf5; --muted:#8e94b3;
    --border:#2c3148; --accent:#7c7cff; --accent-t:#0f111a; --shadow:0 1px 2px rgba(0,0,0,.4),0 6px 16px rgba(0,0,0,.25);
    --low-bg:#14392395; --low-fg:#6fdc99;
    --med-bg:#4a380d95; --med-fg:#f5c555;
    --high-bg:#53191d95; --high-fg:#ff8a90;
  }
  *{box-sizing:border-box}
  html,body{margin:0;min-height:100%}
  body{
    background:var(--bg); color:var(--text);
    font:15px/1.4 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
    transition:background .25s,color .25s;
    display:flex; flex-direction:column; min-height:100vh; overflow-x:hidden;
  }
  header{
    display:flex; flex-wrap:wrap; align-items:center; gap:12px;
    padding:18px 24px;
  }
  .brand{display:flex; align-items:center; gap:10px; font-weight:700; font-size:20px; margin-right:auto}
  .logo{width:30px;height:30px;border-radius:8px;background:linear-gradient(135deg,var(--accent),#e05fd0);display:grid;place-items:center;color:#fff;font-size:16px}
  .search{position:relative; flex:0 1 280px; min-width:140px}
  .search input{
    width:100%; padding:9px 12px 9px 34px; border-radius:10px; border:1px solid var(--border);
    background:var(--surface); color:var(--text); font:inherit; outline:none;
  }
  .search input:focus,.modal input[type=text]:focus{border-color:var(--accent); box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 25%,transparent)}
  .search svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--muted)}
  button{font:inherit;color:inherit;cursor:pointer}
  .btn{padding:9px 16px;border-radius:10px;border:1px solid var(--border);background:var(--surface);font-weight:600}
  .btn:hover{border-color:var(--accent)}
  .btn.primary{background:var(--accent);color:var(--accent-t);border-color:var(--accent)}
  .btn.primary:hover{filter:brightness(1.08)}
  .icon-btn{width:38px;height:38px;border-radius:10px;border:1px solid var(--border);background:var(--surface);display:grid;place-items:center;font-size:17px}
  .icon-btn:hover{border-color:var(--accent)}

  main{
    flex:1; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:18px;
    padding:6px 24px 24px; align-items:start;
  }
  .column{
    background:var(--col); border:2px solid transparent; border-radius:16px; padding:12px;
    transition:border-color .15s, background .15s; min-height:200px;
  }
  .column.over{border-color:var(--accent); background:color-mix(in srgb,var(--accent) 8%,var(--col))}
  .col-head{display:flex;align-items:center;gap:8px;padding:4px 6px 12px}
  .dot{width:10px;height:10px;border-radius:50%}
  .col-head h2{font-size:14px;letter-spacing:.04em;text-transform:uppercase;margin:0;font-weight:700}
  .count{margin-left:auto;background:var(--surface);border:1px solid var(--border);color:var(--muted);
    min-width:26px;text-align:center;padding:1px 8px;border-radius:99px;font-size:13px;font-weight:700}
  .list{display:flex;flex-direction:column;gap:10px;min-height:80px}
  .card{
    background:var(--surface); border:1px solid var(--border); border-radius:12px; padding:12px 12px 12px 14px;
    box-shadow:var(--shadow); cursor:grab; position:relative;
    display:flex; flex-direction:column; gap:10px; animation:pop .25s ease;
    transition:transform .15s, box-shadow .15s;
  }
  .card:hover{transform:translateY(-1px)}
  .card:active{cursor:grabbing}
  .card.dragging{opacity:.35}
  .card::before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:3px;border-radius:3px;background:var(--pc)}
  .card.low{--pc:var(--low-fg)} .card.medium{--pc:var(--med-fg)} .card.high{--pc:var(--high-fg)}
  .card-top{display:flex;gap:8px;align-items:flex-start}
  .card-title{flex:1;font-weight:600;word-break:break-word}
  .del{border:none;background:transparent;color:var(--muted);width:24px;height:24px;border-radius:6px;font-size:16px;line-height:1;opacity:.6;flex:none}
  .del:hover{background:var(--high-bg);color:var(--high-fg);opacity:1}
  .badge{align-self:flex-start;font-size:12px;font-weight:700;padding:2px 10px;border-radius:99px;text-transform:capitalize}
  .badge.low{background:var(--low-bg);color:var(--low-fg)}
  .badge.medium{background:var(--med-bg);color:var(--med-fg)}
  .badge.high{background:var(--high-bg);color:var(--high-fg)}
  .indicator{height:4px;border-radius:4px;background:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 28%,transparent);margin:2px 0;flex:none}
  .empty{color:var(--muted);text-align:center;padding:22px 8px;border:2px dashed var(--border);border-radius:12px;font-size:14px}
  @keyframes pop{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}

  .overlay{position:fixed;inset:0;background:rgba(10,12,25,.5);display:none;align-items:center;justify-content:center;padding:16px;z-index:10;backdrop-filter:blur(2px)}
  .overlay.open{display:flex}
  .modal{background:var(--surface);border:1px solid var(--border);border-radius:16px;padding:22px;width:100%;max-width:400px;box-shadow:0 20px 50px rgba(0,0,0,.35);animation:pop .2s ease}
  .modal h3{margin:0 0 14px;font-size:18px}
  .modal label.l{display:block;font-size:13px;font-weight:600;color:var(--muted);margin:12px 0 6px}
  .modal input[type=text],.modal select{width:100%;padding:10px 12px;border-radius:10px;border:1px solid var(--border);background:var(--bg);color:var(--text);font:inherit;outline:none}
  .seg{display:flex;gap:8px}
  .seg label{flex:1;position:relative}
  .seg input{position:absolute;opacity:0}
  .seg span{display:block;text-align:center;padding:8px 0;border-radius:10px;border:1px solid var(--border);cursor:pointer;font-weight:600;text-transform:capitalize;font-size:14px}
  .seg input:checked+span{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 15%,transparent)}
  .seg input:focus-visible+span{box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 35%,transparent)}
  .err{color:var(--danger);font-size:13px;min-height:18px;margin-top:6px}
  .actions{display:flex;justify-content:flex-end;gap:10px;margin-top:10px}

  @media (max-width:820px){
    main{grid-template-columns:1fr;padding:6px 14px 20px}
    header{padding:14px}
    .search{order:5;flex:1 1 100%}
  }
</style>
</head>
<body>
<header>
  <div class="brand"><div class="logo">▦</div>Sprint Board</div>
  <div class="search">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
    <input id="q" type="search" placeholder="Search cards…" aria-label="Search cards by title" autocomplete="off">
  </div>
  <button class="btn primary" id="addBtn">+ Add card</button>
  <button class="icon-btn" id="themeBtn" aria-label="Toggle theme" title="Toggle theme">🌙</button>
</header>

<main id="board"></main>

<div class="overlay" id="overlay">
  <form class="modal" id="form" role="dialog" aria-modal="true" aria-labelledby="mt" novalidate>
    <h3 id="mt">New card</h3>
    <label class="l" for="title">Title *</label>
    <input type="text" id="title" maxlength="90" placeholder="e.g. Write release notes" autocomplete="off">
    <div class="err" id="err"></div>
    <label class="l">Priority</label>
    <div class="seg">
      <label><input type="radio" name="prio" value="low"><span>low</span></label>
      <label><input type="radio" name="prio" value="medium" checked><span>medium</span></label>
      <label><input type="radio" name="prio" value="high"><span>high</span></label>
    </div>
    <label class="l" for="colSel">Column</label>
    <select id="colSel"></select>
    <div class="actions">
      <button type="button" class="btn" id="cancel">Cancel</button>
      <button type="submit" class="btn primary">Add card</button>
    </div>
  </form>
</div>

<script>
(function(){
  const COLS = [
    {id:'todo', name:'To do', color:'#8e94b3'},
    {id:'doing', name:'In progress', color:'#f5a524'},
    {id:'done', name:'Done', color:'#2fb869'}
  ];
  let nextId = 1;
  const mk = (title, priority, col) => ({id:'c'+(nextId++), title, priority, col});
  let cards = [
    mk('Design onboarding email sequence','medium','todo'),
    mk('Fix checkout crash on Safari 17','high','todo'),
    mk('Migrate analytics to new event schema','medium','doing'),
    mk('Review accessibility audit findings','low','doing'),
    mk('Set up CI pipeline for staging','high','done'),
    mk('Update pricing page copy','low','done')
  ];
  let query = '';
  let dragId = null;

  const board = document.getElementById('board');
  const indicator = document.createElement('div');
  indicator.className = 'indicator';

  function render(){
    board.innerHTML = '';
    const q = query.trim().toLowerCase();
    COLS.forEach(col => {
      const all = cards.filter(c => c.col === col.id);
      const shown = all.filter(c => c.title.toLowerCase().includes(q));
      const sec = document.createElement('section');
      sec.className = 'column'; sec.dataset.col = col.id;
      const head = document.createElement('div'); head.className = 'col-head';
      head.innerHTML = '<span class="dot"></span><h2></h2><span class="count"></span>';
      head.querySelector('.dot').style.background = col.color;
      head.querySelector('h2').textContent = col.name;
      const cnt = head.querySelector('.count');
      cnt.textContent = q ? shown.length + '/' + all.length : all.length;
      cnt.title = all.length + ' card' + (all.length===1?'':'s');
      sec.appendChild(head);
      const list = document.createElement('div'); list.className = 'list';
      shown.forEach(c => list.appendChild(cardEl(c)));
      if(!shown.length){
        const e = document.createElement('div'); e.className = 'empty';
        e.textContent = q && all.length ? 'No matching cards' : 'Drop cards here';
        list.appendChild(e);
      }
      sec.appendChild(list);
      bindColumn(sec, list);
      board.appendChild(sec);
    });
  }

  function cardEl(c){
    const el = document.createElement('article');
    el.className = 'card ' + c.priority; el.draggable = true; el.dataset.id = c.id;
    const top = document.createElement('div'); top.className = 'card-top';
    const t = document.createElement('div'); t.className = 'card-title'; t.textContent = c.title;
    const d = document.createElement('button'); d.className = 'del'; d.type = 'button';
    d.innerHTML = '&times;'; d.setAttribute('aria-label','Delete card: ' + c.title); d.title = 'Delete';
    d.addEventListener('click', () => { cards = cards.filter(x => x.id !== c.id); render(); });
    d.addEventListener('mousedown', e => e.stopPropagation());
    top.append(t, d);
    const b = document.createElement('span'); b.className = 'badge ' + c.priority; b.textContent = c.priority;
    el.append(top, b);
    el.addEventListener('dragstart', e => {
      dragId = c.id;
      e.dataTransfer.effectAllowed = 'move';
      e.dataTransfer.setData('text/plain', c.id);
      setTimeout(() => el.classList.add('dragging'), 0);
    });
    el.addEventListener('dragend', () => { dragId = null; clearDrag(); el.classList.remove('dragging'); });
    return el;
  }

  function clearDrag(){
    indicator.remove();
    document.querySelectorAll('.column.over').forEach(c => c.classList.remove('over'));
  }

  function bindColumn(sec, list){
    sec.addEventListener('dragover', e => {
      if(!dragId) return;
      e.preventDefault(); e.dataTransfer.dropEffect = 'move';
      document.querySelectorAll('.column.over').forEach(c => { if(c !== sec) c.classList.remove('over'); });
      sec.classList.add('over');
      const items = [...list.querySelectorAll('.card:not(.dragging)')];
      let before = null;
      for(const it of items){
        const r = it.getBoundingClientRect();
        if(e.clientY < r.top + r.height/2){ before = it; break; }
      }
      const empty = list.querySelector('.empty');
      if(before){ if(indicator.nextSibling !== before || indicator.parentNode !== list) list.insertBefore(indicator, before); }
      else if(empty){ if(indicator.nextSibling !== empty || indicator.parentNode !== list) list.insertBefore(indicator, empty); }
      else if(list.lastElementChild !== indicator) list.appendChild(indicator);
    });
    sec.addEventListener('dragleave', e => {
      if(!sec.contains(e.relatedTarget)){ sec.classList.remove('over'); if(indicator.parentNode === list) indicator.remove(); }
    });
    sec.addEventListener('drop', e => {
      if(!dragId) return;
      e.preventDefault();
      const next = indicator.parentNode === list ? indicator.nextElementSibling : null;
      const beforeId = next && next.dataset ? next.dataset.id : null;
      const moving = cards.find(c => c.id === dragId);
      if(!moving) return;
      cards = cards.filter(c => c !== moving);
      moving.col = sec.dataset.col;
      let idx;
      if(beforeId && cards.some(c => c.id === beforeId)){
        idx = cards.findIndex(c => c.id === beforeId);
      } else {
        let last = -1;
        cards.forEach((c,i) => { if(c.col === moving.col) last = i; });
        idx = last + 1;
        if(last === -1) idx = cards.length;
      }
      cards.splice(idx, 0, moving);
      dragId = null; clearDrag(); render();
    });
  }

  /* Search */
  document.getElementById('q').addEventListener('input', e => { query = e.target.value; render(); });

  /* Theme */
  const themeBtn = document.getElementById('themeBtn');
  themeBtn.addEventListener('click', () => {
    const dark = document.documentElement.dataset.theme !== 'dark';
    document.documentElement.dataset.theme = dark ? 'dark' : 'light';
    themeBtn.textContent = dark ? '☀️' : '🌙';
  });

  /* Modal */
  const overlay = document.getElementById('overlay');
  const form = document.getElementById('form');
  const titleIn = document.getElementById('title');
  const err = document.getElementById('err');
  const colSel = document.getElementById('colSel');
  COLS.forEach(c => { const o = document.createElement('option'); o.value = c.id; o.textContent = c.name; colSel.appendChild(o); });

  function openModal(){
    form.reset(); err.textContent = ''; colSel.value = 'todo';
    overlay.classList.add('open'); setTimeout(() => titleIn.focus(), 0);
  }
  function closeModal(){ overlay.classList.remove('open'); document.getElementById('addBtn').focus(); }
  document.getElementById('addBtn').addEventListener('click', openModal);
  document.getElementById('cancel').addEventListener('click', closeModal);
  overlay.addEventListener('mousedown', e => { if(e.target === overlay) closeModal(); });
  document.addEventListener('keydown', e => { if(e.key === 'Escape' && overlay.classList.contains('open')) closeModal(); });
  form.addEventListener('submit', e => {
    e.preventDefault();
    const title = titleIn.value.trim();
    if(!title){ err.textContent = 'Please enter a title.'; titleIn.focus(); return; }
    const prio = form.querySelector('input[name=prio]:checked').value;
    cards.push(mk(title, prio, colSel.value));
    overlay.classList.remove('open');
    render();
  });
  titleIn.addEventListener('input', () => err.textContent = '');

  render();
})();
</script>
</body>
</html>
Reasoning trace (981 tokens)
I'm putting together a single-file Kanban board with columns that show card counts, six starter cards, and priority badges. I also want an add modal, delete, drag and drop with a drop indicator between cards, a search filter, and a theme toggle, and I'm weighing whether HTML5 drag and drop or pointer events will work best inside the sandbox.

I'm settling on HTML5 drag and drop with a placeholder line between cards, calculating the drop position from card midpoints and updating the card array when a drop lands. I'll re-render only after the drop, with cleanup on dragend, and keep the search filter working alongside it.

Next I'm setting the theme to CSS variables with a light default, and laying out the header, a three-column board that stacks on narrow screens, and a modal with a priority selector. Then I'll write the code, using textContent for user-entered text. For drag and drop, I'll set the card's data on dragstart and show a placeholder indicator while dragging over a column.

I'm adding a delete button on each card, plus a "+ Add card" action that opens the modal with a column selector.