Cartões, listas e organização de conteúdo

Pesquisa em lista em tempo real

Filtre cidades instantaneamente ao digitar palavras-chave e destaque os resultados correspondentes.

HTMLCSSJavaScriptBuscar
É possível editar, executar e salvar este exemplo após ativar JavaScript. O código-fonte fixo é o seguinte:
<!doctype html>
<html lang="pt-BR" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Pesquisa em lista em tempo real</title>
  <style>
    * { box-sizing: border-box; }
    body { min-height: 100vh; margin: 0; padding: clamp(28px, 6vw, 70px) 20px; color: #242f35; font-family: "Avenir Next", "Microsoft YaHei", sans-serif; background: #e8f0f0; }
    main { width: min(850px, 100%); margin: auto; }
    header { margin-bottom: 28px; }
    .eyebrow { color: #d25c42; font-size: 11px; font-weight: 900; letter-spacing: .18em; }
    h1 { margin: 10px 0 10px; font: 700 clamp(38px, 8vw, 68px)/1 Georgia, "STSong", serif; }
    header p { margin: 0; color: #718087; }
    .search { display: flex; gap: 10px; padding: 9px; border: 1px solid #cad6d7; border-radius: 17px; background: #fff; box-shadow: 0 16px 38px rgba(46,68,72,.08); }
    .search span { display: grid; width: 42px; place-items: center; color: #d25c42; font-size: 22px; }
    input { min-width: 0; flex: 1; border: 0; color: #243138; font: inherit; font-size: 17px; outline: 0; }
    input::placeholder { color: #9aa7aa; }
    .clear { padding: 10px 15px; border: 0; border-radius: 10px; color: #66777c; font: inherit; font-weight: 750; background: #edf2f2; cursor: pointer; }
    .meta { display: flex; justify-content: space-between; gap: 16px; margin: 20px 2px 12px; color: #718087; font-size: 12px; }
    .meta strong { color: #d25c42; }
    .list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
    article { display: grid; grid-template-columns: 48px 1fr auto; gap: 14px; align-items: center; padding: 16px; border: 1px solid #d3ddde; border-radius: 16px; background: rgba(255,255,255,.75); transition: transform .18s ease, background .18s ease; }
    article:hover { transform: translateY(-3px); background: #fff; }
    .code { display: grid; width: 48px; height: 48px; place-items: center; border-radius: 13px; color: #fff; font: 800 12px/1 Georgia, serif; background: var(--color); }
    h2 { margin: 0 0 4px; font: 700 19px/1.2 Georgia, "STSong", serif; }
    article p { margin: 0; color: #849196; font-size: 12px; }
    .temperature { color: #53636a; font-size: 13px; font-weight: 800; }
    mark { padding: 1px 2px; color: inherit; background: #ffd7a3; border-radius: 3px; }
    .empty { grid-column: 1 / -1; padding: 58px 20px; border: 1px dashed #b9c8ca; border-radius: 18px; color: #718087; text-align: center; }
    @media (max-width: 650px) { .list { grid-template-columns: 1fr; } }
    @media (max-width: 420px) { article { grid-template-columns: 42px 1fr; } .temperature { grid-column: 2; } }
    @media (prefers-reduced-motion: reduce) { article { transition: none; } }
  </style>
</head>
<body>
  <main>
    <header><span class="eyebrow">CITY WEATHER INDEX</span><h1>Para onde ir hoje?</h1><p>Pesquise por nome da cidade, pinyin ou província, e a lista será atualizada instantaneamente.</p></header>
    <div class="search"><span aria-hidden="true">⌕</span><input id="query" type="search" aria-label="Pesquisar cidade" placeholder="Por exemplo: Hangzhou, chengdu, Guangdong" autocomplete="off"><button id="clear" class="clear" type="button">Limpar</button></div>
    <div class="meta"><span>Cidades correspondentes</span><span><strong id="count">0</strong>  resultados</span></div>
    <section id="list" class="list" aria-live="polite"></section>
  </main>
  <script>
    const cities = [
      { name: 'Pequim', pinyin: 'beijing', province: 'Pequim', code: 'BJ', weather: 'Ensolarado', temp: '29°', color: '#d86a45' },
      { name: 'São Paulo', pinyin: 'shanghai', province: 'São Paulo', code: 'SH', weather: 'Parcialmente nublado', temp: '31°', color: '#547c99' },
      { name: 'Hangzhou', pinyin: 'hangzhou', province: 'Zhejiang', code: 'HZ', weather: 'Chuva passageira', temp: '28°', color: '#4d8b72' },
      { name: 'Chengdu', pinyin: 'chengdu', province: 'Sichuan', code: 'CD', weather: 'Yin', temp: '26°', color: '#8a7753' },
      { name: 'Xiamen', pinyin: 'xiamen', province: 'Fujian', code: 'XM', weather: 'Ensolarado', temp: '30°', color: '#3e8e9b' },
      { name: 'Qingdao', pinyin: 'qingdao', province: 'Shandong', code: 'QD', weather: 'Brisa do mar', temp: '25°', color: '#4672a1' },
      { name: 'Guangzhou', pinyin: 'guangzhou', province: 'Guangdong', code: 'GZ', weather: 'Tempestade', temp: '32°', color: '#9b5e70' },
      { name: 'Dali', pinyin: 'dali', province: 'Yunnan', code: 'DL', weather: 'Ensolarado', temp: '23°', color: '#687a43' }
    ];
    const queryInput = document.querySelector('#query');
    const list = document.querySelector('#list');
    const count = document.querySelector('#count');

    function appendHighlighted(target, text, query) {
      const index = text.toLocaleLowerCase().indexOf(query);
      if (!query || index < 0) { target.textContent = text; return; }
      target.append(document.createTextNode(text.slice(0, index)));
      const mark = document.createElement('mark');
      mark.textContent = text.slice(index, index + query.length);
      target.append(mark, document.createTextNode(text.slice(index + query.length)));
    }
    function createCard(city, query) {
      const article = document.createElement('article');
      const code = document.createElement('span'); code.className = 'code'; code.style.setProperty('--color', city.color); code.textContent = city.code;
      const info = document.createElement('div');
      const title = document.createElement('h2'); appendHighlighted(title, city.name, query);
      const detail = document.createElement('p'); appendHighlighted(detail, `${city.province} · ${city.pinyin} · ${city.weather}`, query);
      const temp = document.createElement('span'); temp.className = 'temperature'; temp.textContent = city.temp;
      info.append(title, detail); article.append(code, info, temp); return article;
    }
    function render() {
      const query = queryInput.value.trim().toLocaleLowerCase();
      const matches = cities.filter(city => `${city.name} ${city.pinyin} ${city.province}`.toLocaleLowerCase().includes(query));
      list.replaceChildren(...matches.map(city => createCard(city, query)));
      count.textContent = String(matches.length);
      if (!matches.length) { const empty = document.createElement('p'); empty.className = 'empty'; empty.textContent = 'Não foram encontrados cidades correspondentes, tente uma palavra-chave mais curta.'; list.append(empty); }
    }
    queryInput.addEventListener('input', render);
    document.querySelector('#clear').addEventListener('click', () => { queryInput.value = ''; queryInput.focus(); render(); });
    render();
  </script>
</body>
</html>
Feedback da páginaEncontrou um problema ou tem uma sugestão de melhoria?
Recursos de feedback precisam ser usados na versão online

Envie somente após ativar JavaScript na versão online; a funcionalidade local da ferramenta ou do exemplo não é afetada.

Ir para o feedback na versão online