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

Painel sanfonado

Componente de acordeão para perguntas frequentes com suporte a teclado e expansão suave.

HTMLCSSJavaScriptacessibilidade
É 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>Painel sanfonado</title>
  <style>
    * { box-sizing: border-box; }
    body {
      min-height: 100vh;
      margin: 0;
      padding: clamp(24px, 7vw, 76px) 20px;
      color: #18302a;
      font-family: "Gill Sans", "Microsoft YaHei", sans-serif;
      background: linear-gradient(135deg, #f4f0d8 0 55%, #d7ead5 55%);
    }
    main { width: min(820px, 100%); margin: auto; }
    header { display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: end; margin-bottom: 34px; }
    .kicker { color: #d5523f; font-size: 12px; font-weight: 800; letter-spacing: .2em; }
    h1 { margin: 8px 0 0; font: 800 clamp(36px, 8vw, 66px)/1 "STKaiti", "KaiTi", serif; }
    .leaf { width: 80px; height: 80px; border-radius: 80% 10% 80% 10%; background: #2e8169; transform: rotate(10deg); box-shadow: inset 14px 14px rgba(255,255,255,.16); }
    .accordion { border-top: 2px solid #18302a; }
    .item { border-bottom: 1px solid rgba(24, 48, 42, .35); }
    .trigger {
      width: 100%;
      display: grid;
      grid-template-columns: 48px 1fr 34px;
      gap: 12px;
      align-items: center;
      padding: 24px 4px;
      border: 0;
      color: inherit;
      text-align: left;
      font: inherit;
      font-size: 19px;
      font-weight: 750;
      background: transparent;
      cursor: pointer;
    }
    .index { color: #d5523f; font: 700 13px/1 Georgia, serif; }
    .plus { position: relative; width: 28px; height: 28px; border: 1px solid currentColor; border-radius: 50%; transition: transform .25s ease; }
    .plus::before, .plus::after { content: ""; position: absolute; left: 7px; right: 7px; top: 13px; height: 1px; background: currentColor; }
    .plus::after { transform: rotate(90deg); transition: opacity .2s ease; }
    .trigger[aria-expanded="true"] .plus { transform: rotate(90deg); color: #d5523f; }
    .trigger[aria-expanded="true"] .plus::after { opacity: 0; }
    .trigger:focus-visible { outline: 3px solid #d5523f; outline-offset: -3px; }
    .panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s ease; }
    .panel.is-open { grid-template-rows: 1fr; }
    .panel-content { overflow: hidden; }
    .panel p { max-width: 650px; margin: 0; padding: 0 48px 24px 64px; color: #4d625c; line-height: 1.8; }
    @media (max-width: 520px) { header { grid-template-columns: 1fr; } .leaf { display: none; } .panel p { padding-left: 4px; } }
    @media (prefers-reduced-motion: reduce) { .panel, .plus { transition: none; } }
  </style>
</head>
<body>
  <main>
    <header>
      <div><span class="kicker">GARDEN NOTES</span><h1>Perguntas frequentes</h1></div>
      <div class="leaf" aria-hidden="true"></div>
    </header>
    <section class="accordion">
      <div class="item">
        <button id="trigger-1" class="trigger" type="button" aria-expanded="true" aria-controls="panel-1"><span class="index">01</span><span>Como escolher o local para plantas de interior?</span><span class="plus" aria-hidden="true"></span></button>
        <div id="panel-1" class="panel is-open" role="region" aria-labelledby="trigger-1" aria-hidden="false"><div class="panel-content"><p>Observe primeiro as mudanças da luz natural ao longo do dia. A maioria das plantas de folhagem prefere luz indireta clara, sem sol direto, e ficar a um ou dois metros de uma janela voltada para o sul costuma ser um ponto de partida confortável.</p></div></div>
      </div>
      <div class="item">
        <button id="trigger-2" class="trigger" type="button" aria-expanded="false" aria-controls="panel-2"><span class="index">02</span><span>Com que frequência devo regar? É o ideal?</span><span class="plus" aria-hidden="true"></span></button>
        <div id="panel-2" class="panel" role="region" aria-labelledby="trigger-2" aria-hidden="true"><div class="panel-content"><p>Não olhe apenas o calendário. Introduza o dedo cerca de dois centímetros no solo; regue bem apenas quando a camada superficial estiver seca. No inverno, a evaporação é mais lenta, então o intervalo deve ser maior.</p></div></div>
      </div>
      <div class="item">
        <button id="trigger-3" class="trigger" type="button" aria-expanded="false" aria-controls="panel-3"><span class="index">03</span><span>O que fazer quando as bordas das folhas ficam amarelas?</span><span class="plus" aria-hidden="true"></span></button>
        <div id="panel-3" class="panel" role="region" aria-labelledby="trigger-3" aria-hidden="true"><div class="panel-content"><p>Primeiro, verifique acúmulo de água, ar excessivamente seco e exposição repentina ao sol forte. Remova as folhas muito danificadas e mantenha boa ventilação; normalmente, em uma a duas semanas, já é possível ver novas folhas se recuperando.</p></div></div>
      </div>
      <div class="item">
        <button id="trigger-4" class="trigger" type="button" aria-expanded="false" aria-controls="panel-4"><span class="index">04</span><span>Quando é necessário trocar o vaso da planta?</span><span class="plus" aria-hidden="true"></span></button>
        <div id="panel-4" class="panel" role="region" aria-labelledby="trigger-4" aria-hidden="true"><div class="panel-content"><p>Quando as raízes saírem pelos furos de drenagem, a água escorrer rapidamente ou o crescimento ficar visivelmente estagnado, você pode trocar, na primavera, para um novo vaso com dois a quatro centímetros a mais de diâmetro.</p></div></div>
      </div>
    </section>
  </main>
  <script>
    const triggers = [...document.querySelectorAll('.trigger')];
    triggers.forEach((trigger, index) => {
      trigger.addEventListener('click', () => {
        const willOpen = trigger.getAttribute('aria-expanded') !== 'true';
        triggers.forEach(item => {
          item.setAttribute('aria-expanded', 'false');
          const panel = document.getElementById(item.getAttribute('aria-controls'));
          panel.classList.remove('is-open');
          panel.setAttribute('aria-hidden', 'true');
        });
        if (willOpen) {
          trigger.setAttribute('aria-expanded', 'true');
          const panel = document.getElementById(trigger.getAttribute('aria-controls'));
          panel.classList.add('is-open');
          panel.setAttribute('aria-hidden', 'false');
        }
      });
      trigger.addEventListener('keydown', event => {
        const direction = event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;
        if (direction) {
          event.preventDefault();
          triggers[(index + direction + triggers.length) % triggers.length].focus();
        }
      });
    });
  </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