SWCore

Modal Componentes

Janela que abre por cima da página, com fundo escurecido: confirmar, avisar, mostrar um formulário rápido. <div sw-modal id='aviso'> + <button sw-modal-open='#aviso'>.

O que é

O modal é aquela janelinha que aparece no meio da tela e escurece o resto: "Tem certeza que quer excluir?", "Deixe seu e-mail", "Veja os detalhes do plano". Você escreve a janela no HTML (ela fica escondida) com sw-modal e um id, e em qualquer botão da página coloca sw-modal-open="#id". Dentro, peças prontas: cabeçalho com título e ×, corpo e rodapé com os botões. Com palavras no valor de sw-modal você escolhe o tamanho, o jeito de entrar (deslizando, com zoom, como gaveta lateral) e o vidro.

O JavaScript do núcleo abre e fecha a janela colocando a classe is-active. Enquanto aberta: a rolagem da página trava, a tecla Tab fica presa dentro da janela, e ela fecha com Esc, com clique no fundo escuro, no × (sw-modal-cls) ou em qualquer coisa marcada com sw-modal-close. Ao fechar, o foco volta para o botão que abriu. Leitores de tela já recebem role="dialog" e aria-modal. Funciona no tema claro e no escuro.

Quando usar

  • Confirmar ação importante: excluir, cancelar pedido, sair sem salvar.
  • Formulário curto sem sair da página: newsletter, "me ligue", login rápido.
  • Detalhes que não cabem no cartão: descrição de plano, política de troca, vídeo.
  • Para aviso rápido que some sozinho, use o Alerta. Para painel lateral de filtros/carrinho, prefira o Panel.

Comece aqui

  1. 1

    Coloque o SWCore na página: CSS no <head> e JS no fim do <body>. O modal precisa dos dois.

    <link rel="stylesheet" href="https://swcore.sanweb.com.br/dist/2.1.0/swcore.min.css">
    
    <!-- fim do <body> -->
    <script src="https://swcore.sanweb.com.br/dist/2.1.0/swcore.min.js"></script>
  2. 2

    Escreva o botão com sw-modal-open="#id" e a janela com o mesmo id. O × e o "Cancelar" fecham porque têm sw-modal-close. Clique para testar.

    Agendar visita

    Escolha um horário e um corretor entra em contato para confirmar.

    <button type="button" sw-btn="pri" sw-modal-open="#agendar">Agendar visita</button>
    
    <div sw-modal id="agendar">
      <div sw-modal-box>
        <div sw-modal-hdr>
          <h4 sw-modal-ttl>Agendar visita</h4>
          <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button>
        </div>
        <div sw-modal-bdy><p>Escolha um horário e um corretor entra em contato para confirmar.</p></div>
        <div sw-modal-ftr>
          <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button>
          <button type="button" sw-btn="pri" sw-modal-close>Quero agendar</button>
        </div>
      </div>
    </div>

Todas as variações

Cada quadro abaixo é o componente de verdade, rodando. O código embaixo é exatamente o que está no quadro: copie e cole.

1. Tamanhos

Sem palavra de tamanho, a janela tem até 600 px de largura. pp 320 px, p 460 px, g 760 px, gg 960 px, xg 80% da tela (largura e altura), fl tela inteira. No celular todas ocupam a largura disponível.

Sair da conta?

Você vai precisar entrar de novo.

pp — bem pequena (320 px) <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-pp">Abrir pp</button> <div sw-modal="pp" id="mdl-t-pp"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Sair da conta?</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Você vai precisar entrar de novo.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

Newsletter

Receba as promoções da semana no seu e-mail.

p — pequena (460 px) <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-p">Abrir p</button> <div sw-modal="p" id="mdl-t-p"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Newsletter</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Receba as promoções da semana no seu e-mail.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

Política de troca

Trocas em até 30 dias com a etiqueta. O frete da primeira troca é por nossa conta.

Padrão — até 600 px <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-m">Abrir padrão</button> <div sw-modal id="mdl-t-m"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Política de troca</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Trocas em até 30 dias com a etiqueta. O frete da primeira troca é por nossa conta.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

Plano Profissional

Site com até 10 páginas, blog, formulários, integração com WhatsApp e suporte mensal.

g — grande (760 px) <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-g">Abrir g</button> <div sw-modal="g" id="mdl-t-g"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Plano Profissional</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Site com até 10 páginas, blog, formulários, integração com WhatsApp e suporte mensal.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

Comparar planos

Básico, Profissional e Empresa lado a lado — use o espaço para uma tabela.

gg — muito grande (960 px) <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-gg">Abrir gg</button> <div sw-modal="gg" id="mdl-t-gg"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Comparar planos</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Básico, Profissional e Empresa lado a lado — use o espaço para uma tabela.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

Contrato de serviço

Janela alta para textos longos: termos, contratos, relatórios.

xg — 80% da tela <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-xg">Abrir xg</button> <div sw-modal="xg" id="mdl-t-xg"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Contrato de serviço</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Janela alta para textos longos: termos, contratos, relatórios.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

Galeria do imóvel

Ocupa a tela toda, sem cantos — bom no celular e para mídia.

fl — tela inteira <button type="button" sw-btn="pri p" sw-modal-open="#mdl-t-fl">Abrir fl</button> <div sw-modal="fl" id="mdl-t-fl"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Galeria do imóvel</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Ocupa a tela toda, sem cantos — bom no celular e para mídia.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Cancelar</button> <button type="button" sw-btn="pri" sw-modal-close>Confirmar</button> </div> </div> </div>

2. Jeito de entrar

Sem palavra, a janela cresce levemente ao abrir. sld desce do alto, zoo nasce pequena e cresce, drw vira uma gaveta que entra pela direita, na altura toda da tela.

Pedido enviado

Você vai receber a confirmação por e-mail.

Padrão — cresce de leve <button type="button" sw-btn="pri p" sw-modal-open="#mdl-e-pad">Abrir</button> <div sw-modal id="mdl-e-pad"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Pedido enviado</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Você vai receber a confirmação por e-mail.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="pri" sw-modal-close>Ok</button> </div> </div> </div>

Cupom liberado

Use VOLTA10 e ganhe 10% na próxima compra.

sld — desce do alto <button type="button" sw-btn="pri p" sw-modal-open="#mdl-e-sld">Abrir sld</button> <div sw-modal="sld" id="mdl-e-sld"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Cupom liberado</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Use VOLTA10 e ganhe 10% na próxima compra.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="pri" sw-modal-close>Ok</button> </div> </div> </div>

Parabéns!

Seu cadastro foi concluído.

zoo — zoom <button type="button" sw-btn="pri p" sw-modal-open="#mdl-e-zoo">Abrir zoo</button> <div sw-modal="zoo" id="mdl-e-zoo"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Parabéns!</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Seu cadastro foi concluído.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="suc" sw-modal-close>Começar</button> </div> </div> </div>

Filtros

Tamanho, cor e faixa de preço ficariam aqui.

drw — gaveta pela direita <button type="button" sw-btn="pri p" sw-modal-open="#mdl-e-drw">Abrir drw</button> <div sw-modal="drw" id="mdl-e-drw"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Filtros</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Tamanho, cor e faixa de preço ficariam aqui.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Limpar</button> <button type="button" sw-btn="pri" sw-modal-close>Aplicar</button> </div> </div> </div>

3. Vidro e combinações

gls deixa a caixa translúcida, mostrando a página desfocada atrás. As palavras se combinam no mesmo atributo, em qualquer ordem: tamanho + entrada + vidro.

Assista ao vídeo

Conheça a clínica em 1 minuto.

gls — caixa de vidro <button type="button" sw-btn="pri p" sw-modal-open="#mdl-c-gls">Abrir gls</button> <div sw-modal="gls" id="mdl-c-gls"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Assista ao vídeo</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Conheça a clínica em 1 minuto.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="glass" sw-modal-close>Fechar</button> </div> </div> </div>

Excluir foto?

A foto sai da galeria do seu site.

p sld — pequena, descendo <button type="button" sw-btn="pri p" sw-modal-open="#mdl-c-psld">Abrir p sld</button> <div sw-modal="p sld" id="mdl-c-psld"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Excluir foto?</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>A foto sai da galeria do seu site.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="ghost" sw-modal-close>Manter</button><button type="button" sw-btn="err" sw-modal-close>Excluir</button> </div> </div> </div>

Tudo certo

Dados salvos.

pp zoo gls — tudo junto <button type="button" sw-btn="pri p" sw-modal-open="#mdl-c-all">Abrir pp zoo gls</button> <div sw-modal="pp zoo gls" id="mdl-c-all"> <div sw-modal-box> <div sw-modal-hdr> <h4 sw-modal-ttl>Tudo certo</h4> <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button> </div> <div sw-modal-bdy><p>Dados salvos.</p></div> <div sw-modal-ftr> <button type="button" sw-btn="pri" sw-modal-close>Ok</button> </div> </div> </div>

4. Peças opcionais

Só a caixa sw-modal-box é obrigatória. Cabeçalho, corpo e rodapé são opcionais — use o que precisar. Sem o ×, a pessoa fecha pelo fundo, pelo Esc ou por um botão com sw-modal-close.

Clique no fundo escuro ou aperte Esc para fechar.

Sem cabeçalho nem rodapé <button type="button" sw-btn="pri p" sw-modal-open="#simples">Abrir simples</button> <div sw-modal="p" id="simples"> <div sw-modal-box> <p>Clique no fundo escuro ou aperte Esc para fechar.</p> </div> </div>

Termos de uso

1. O serviço é prestado conforme o plano contratado.

2. O pagamento é mensal, com vencimento todo dia 10.

3. O cancelamento pode ser pedido a qualquer momento, sem multa.

4. Os dados são tratados conforme a LGPD.

5. Backups diários são mantidos por 30 dias.

6. O suporte atende de segunda a sexta, das 9h às 18h.

7. Alterações nestes termos são avisadas por e-mail.

8. Fica eleito o foro da comarca de Belo Horizonte.

Corpo longo que rola <!-- o corpo (sw-modal-bdy) rola sozinho quando passa de 60% da altura da tela --> <div sw-modal id="termos"> <div sw-modal-box> <div sw-modal-hdr>…</div> <div sw-modal-bdy>…texto longo…</div> <div sw-modal-ftr><button type="button" sw-btn="pri" sw-modal-close>Li e aceito</button></div> </div> </div>

Tabela de opções

PalavraO que fazExemplo
Peças
sw-modalO fundo escuro que cobre a tela; precisa de um id. O valor recebe as palavras de tamanho/efeito.<div sw-modal id="aviso">
sw-modal-boxA caixa branca/escura da janela. Obrigatória.<div sw-modal-box>
sw-modal-hdrCabeçalho (título à esquerda, × à direita).<div sw-modal-hdr>
sw-modal-ttlTítulo.<h4 sw-modal-ttl>
sw-modal-clsDesenha o × e fecha ao clicar (sozinho já basta; com sw-modal-close junto continua valendo).<button sw-modal-cls sw-modal-close aria-label="Fechar">
sw-modal-bdyCorpo; rola se passar de 60% da altura da tela.<div sw-modal-bdy>
sw-modal-ftrRodapé com os botões, alinhados à direita.<div sw-modal-ftr>
Abrir e fechar
sw-modal-openEm qualquer botão/link: abre o modal do id indicado (começando com #).<button sw-modal-open="#aviso">
sw-modal-closeEm qualquer elemento dentro do modal: clicar nele fecha.<button sw-modal-close>
(clique no fundo)Clicar fora da caixa fecha.
EscA tecla Esc fecha.
autofocusNum campo dentro do modal: recebe o cursor ao abrir.<input sw-inp autofocus>
Tamanho
ppAté 320 px.sw-modal="pp"
pAté 460 px.sw-modal="p"
(nenhum)Até 600 px.sw-modal
gAté 760 px.sw-modal="g"
ggAté 960 px.sw-modal="gg"
xg80% da largura e da altura da tela.sw-modal="xg"
flTela inteira, sem cantos.sw-modal="fl"
Entrada
(nenhum)Cresce de leve.
sldDesce do alto.sw-modal="sld"
zooZoom: nasce pequena e cresce.sw-modal="zoo"
drwGaveta pela direita, altura toda (420 px de largura).sw-modal="drw"
Visual
glsCaixa de vidro translúcido.sw-modal="gls"

Receitas prontas — usos reais

Situações que aparecem em quase todo site. Copie a que servir.

Confirmar exclusão (painel admin) Ao vivo

Excluir "Maria Souza"?

O histórico de agendamentos dela também será apagado. Não dá para desfazer.

<button type="button" sw-btn="err out" sw-modal-open="#excluir"><i class="swi-trash"></i> Excluir cliente</button>

<div sw-modal="p sld" id="excluir">
  <div sw-modal-box>
    <div sw-modal-hdr>
      <h4 sw-modal-ttl>Excluir "Maria Souza"?</h4>
      <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button>
    </div>
    <div sw-modal-bdy><p>O histórico de agendamentos dela também será apagado. Não dá para desfazer.</p></div>
    <div sw-modal-ftr>
      <button type="button" sw-btn="ghost" sw-modal-close>Manter</button>
      <button type="button" sw-btn="err" id="confirmar-exclusao"><i class="swi-trash"></i> Excluir de vez</button>
    </div>
  </div>
</div>

<script>
  document.getElementById('confirmar-exclusao').addEventListener('click', async () => {
    await fetch('/admin/clientes/42', { method: 'DELETE' });
    SW.Modal.hide('#excluir');
    SW.Alert.ok('Cliente excluído.');
  });
</script>
Formulário rápido: "Me liga" Ao vivo

A gente te liga

<button type="button" sw-btn="suc" sw-modal-open="#me-liga"><i class="swi-phone"></i> Quero que me liguem</button>

<div sw-modal="p" id="me-liga">
  <div sw-modal-box>
    <div sw-modal-hdr>
      <h4 sw-modal-ttl>A gente te liga</h4>
      <button type="button" sw-modal-cls sw-modal-close aria-label="Fechar"></button>
    </div>
    <form sw-frm action="/me-liga" method="post">
      <div sw-fld><label for="nome">Nome</label><input sw-inp id="nome" name="nome" autofocus></div>
      <div sw-fld><label for="tel">Telefone</label><input sw-inp id="tel" name="tel" type="tel"></div>
      <div sw-modal-ftr><button type="submit" sw-btn="suc">Pedir ligação</button></div>
    </form>
  </div>
</div>
Abrir sozinho uma vez (promoção na entrada) Referência
<div sw-modal="p zoo" id="promo">
  <div sw-modal-box>…Cupom BEMVINDO10…</div>
</div>

<script>
  document.addEventListener('sw:ready', () => {
    if (localStorage.getItem('promo-vista')) return;
    setTimeout(() => SW.Modal.show('#promo'), 3000);   // abre depois de 3 segundos
    localStorage.setItem('promo-vista', '1');
  });
</script>
Saber quando abriu e fechou (eventos) Referência
const video = document.getElementById('modal-video');

video.addEventListener('sw:modal:open', () => {
  video.querySelector('video').play();
});
video.addEventListener('sw:modal:close', () => {
  video.querySelector('video').pause();   // não deixa o vídeo tocando escondido
});

Eventos

sw:modal:open
Disparado no [sw-modal] quando ele abre.
sw:modal:close
Disparado no [sw-modal] quando ele fecha (por qualquer caminho, inclusive se ele sair da página ainda aberto).

API (JavaScript)

SW.Modal.show('#id')
Abre o modal. Aceita seletor ou o próprio elemento. Devolve true se abriu, false se já estava aberto ou não existe.
SW.Modal.hide('#id')
Fecha o modal. Devolve true se fechou.
SW.Modal.initAll(raiz)
Liga os botões sw-modal-open e os modais dentro de raiz. O núcleo já faz sozinho.

Precisa de quê

  • swcore.min.css + swcore.min.js.
  • swcore.compl.min.css — só se usar ícones swi-* nos botões.

Cuidados — erros comuns

  • sw-modal-open sem o # (sw-modal-open="aviso"): não abre. Tem que ser "#aviso".
  • Dois modais com o mesmo id: o botão sempre abre o primeiro.
  • Botão "Salvar" dentro de um <form> no modal com sw-modal-close: fecha antes de você tratar o envio. Feche pelo código (SW.Modal.hide) depois de salvar.
  • Usar SWModal.show(): o nome certo é SW.Modal.show().

O que ele não faz

  • Não dá para impedir o fechamento pelo fundo escuro ou pelo Esc (não existe modo "obrigatório").
  • Não abre um modal dentro de outro de forma organizada (o segundo fica por cima, mas o Esc fecha os dois).
  • Não carrega conteúdo de outra página sozinho: o HTML da janela precisa estar na página (ou ser colocado por você antes de abrir).