Guia de Uso - Loader
Status: Implementado (Design System 1.0 - 02/02/2026) - Componente de loading com spinner circular e icone central.
Indice
- Introducao
- Estrutura Base
- Tamanhos
- Variantes de Cor
- Modo Progress
- Dark Mode
- Uso com Modal
- JavaScript
- Exemplos Praticos
Introducao
O componente Loader e utilizado para indicar operacoes em andamento. Diferente do spinner simples, possui:
- Circulo animado com arco de progresso
- Icone central (customizavel)
- Titulo e subtitulo descritivos
- Suporte completo a dark/light mode
Quando Usar Loader
Use loader quando:
- Uma operacao demora mais de 1-2 segundos
- Deseja mostrar progresso visual com contexto
- Precisa de feedback ao usuario com descricao
- A operacao tem etapas que podem ser descritas
Evite usar loader quando:
- A operacao e instantanea (use skeleton ou nada)
- Nao ha contexto para mostrar (use spinner simples)
- O espaco e muito pequeno (use spinner ou progress)
Estrutura Base
HTML Basico
html
<div class="loader">
<!-- Spinner com Ring e Icone -->
<div class="loader__spinner">
<!-- Ring SVG -->
<div class="loader__ring">
<svg viewBox="0 0 96 96">
<circle class="loader__ring-track" cx="48" cy="48" r="44"></circle>
<circle class="loader__ring-arc" cx="48" cy="48" r="44"></circle>
</svg>
</div>
<!-- Icone Central -->
<div class="loader__icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
<polyline points="10 9 9 9 8 9"/>
</svg>
</div>
</div>
<!-- Conteudo de Texto -->
<div class="loader__content">
<h3 class="loader__title">Gerando documento...</h3>
<p class="loader__subtitle">Validando e-mail</p>
</div>
</div>Classes Principais
| Classe | Descricao |
|---|---|
.loader | Container principal |
.loader__spinner | Container do spinner (ring + icone) |
.loader__ring | SVG do anel animado |
.loader__ring-track | Circulo de fundo (track) |
.loader__ring-arc | Arco animado de progresso |
.loader__icon | Container do icone central |
.loader__content | Container dos textos |
.loader__title | Titulo principal |
.loader__subtitle | Subtitulo/descricao |
Tamanhos
Small (64px)
html
<div class="loader loader--sm">
...
</div>Medium - Padrao (96px)
html
<div class="loader">
...
</div>Large (128px)
html
<div class="loader loader--lg">
...
</div>Variantes de Cor
O arco de progresso usa --color-primary (vermelho) por padrao. Variantes disponiveis:
Primary (Padrao - Vermelho)
html
<div class="loader">
<!-- Arco vermelho #970707 -->
</div>Success (Verde)
html
<div class="loader loader--success">
<!-- Arco verde #519000 -->
</div>Info (Azul)
html
<div class="loader loader--info">
<!-- Arco azul #3E68FB -->
</div>Warning (Amarelo)
html
<div class="loader loader--warning">
<!-- Arco amarelo #E9BD00 -->
</div>Danger (Vermelho Alerta)
html
<div class="loader loader--danger">
<!-- Arco vermelho #C90A0A -->
</div>Modo Progress
Para mostrar progresso real (nao infinito), use a classe .loader--progress:
html
<div class="loader loader--progress">
<div class="loader__spinner">
<div class="loader__ring">
<svg viewBox="0 0 96 96">
<circle class="loader__ring-track" cx="48" cy="48" r="44"></circle>
<circle class="loader__ring-arc" cx="48" cy="48" r="44"
style="stroke-dashoffset: 138.23"></circle>
</svg>
</div>
<div class="loader__icon">...</div>
</div>
<div class="loader__content">
<h3 class="loader__title">Processando...</h3>
<p class="loader__subtitle">50% concluido</p>
</div>
</div>Calculo do Progresso
javascript
// Circunferencia = 2 * PI * raio (44)
const radius = 44;
const circumference = 2 * Math.PI * radius; // ~276.46
// Offset = (100 - percentual) / 100 * circunferencia
function calculateOffset(percent) {
return ((100 - percent) / 100) * circumference;
}
// Exemplos:
// 0% -> offset = 276.46 (circulo vazio)
// 25% -> offset = 207.35
// 50% -> offset = 138.23
// 75% -> offset = 69.12
// 100% -> offset = 0 (circulo completo)Dark Mode
O componente suporta dark mode automaticamente atraves das variaveis CSS. Nao e necessario fazer nada adicional.
Cores no Dark Mode
| Elemento | Light Mode | Dark Mode |
|---|---|---|
| Background (fullscreen) | #F6F6F9 | #10141D |
| Ring Track | #CED3E2 | #2A2F41 |
| Ring Arc | #970707 | #970707 |
| Icon Background | #ECEDF2 | #1D2333 |
| Icon Color | #394360 | #A2A8B9 |
| Title | #12151F | #E0E2EB |
| Subtitle | #394360 | #A2A8B9 |
Uso com Modal
Dentro de um Modal
html
<div class="modal modal--active">
<div class="loader loader--modal">
<!-- Estrutura do loader -->
</div>
</div>Fullscreen (Tela Inteira)
html
<div class="loader loader--fullscreen">
<!-- Estrutura do loader -->
</div>JavaScript
Funcao Helper para Exibir/Ocultar
javascript
/**
* Mostra o loader com titulo e subtitulo personalizados
* @param {Object} options - Opcoes do loader
* @param {string} options.title - Titulo principal
* @param {string} options.subtitle - Subtitulo/descricao
* @param {string} options.icon - HTML do icone (opcional)
* @param {string} options.variant - Variante de cor (opcional)
*/
function showLoader(options = {}) {
const {
title = 'Carregando...',
subtitle = '',
icon = null,
variant = ''
} = options;
// Remove loader existente
hideLoader();
const loaderHTML = `
<div class="loader loader--fullscreen loader--fade-in ${variant ? 'loader--' + variant : ''}" id="app-loader">
<div class="loader__spinner">
<div class="loader__ring">
<svg viewBox="0 0 96 96">
<circle class="loader__ring-track" cx="48" cy="48" r="44"></circle>
<circle class="loader__ring-arc" cx="48" cy="48" r="44"></circle>
</svg>
</div>
<div class="loader__icon">
${icon || getDefaultIcon()}
</div>
</div>
<div class="loader__content">
<h3 class="loader__title">${title}</h3>
${subtitle ? `<p class="loader__subtitle">${subtitle}</p>` : ''}
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', loaderHTML);
}
/**
* Oculta o loader
*/
function hideLoader() {
const loader = document.getElementById('app-loader');
if (loader) {
loader.classList.add('loader--fade-out');
loader.addEventListener('animationend', () => loader.remove());
}
}
/**
* Atualiza o texto do loader
* @param {string} title - Novo titulo
* @param {string} subtitle - Novo subtitulo
*/
function updateLoader(title, subtitle) {
const loader = document.getElementById('app-loader');
if (loader) {
const titleEl = loader.querySelector('.loader__title');
const subtitleEl = loader.querySelector('.loader__subtitle');
if (titleEl) titleEl.textContent = title;
if (subtitleEl) subtitleEl.textContent = subtitle;
}
}
/**
* Icone padrao (documento)
*/
function getDefaultIcon() {
return `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
<polyline points="10 9 9 9 8 9"/>
</svg>
`;
}Exemplo de Uso
javascript
// Mostrar loader simples
showLoader({ title: 'Carregando...' });
// Mostrar loader com detalhes
showLoader({
title: 'Gerando documento...',
subtitle: 'Validando e-mail'
});
// Mostrar loader com variante
showLoader({
title: 'Enviando dados...',
subtitle: 'Aguarde',
variant: 'primary'
});
// Atualizar texto durante operacao
updateLoader('Processando...', 'Etapa 2 de 3');
// Ocultar loader
hideLoader();Exemplos Praticos
Exemplo 1: Geracao de Documento
html
<div class="loader">
<div class="loader__spinner">
<div class="loader__ring">
<svg viewBox="0 0 96 96">
<circle class="loader__ring-track" cx="48" cy="48" r="44"></circle>
<circle class="loader__ring-arc" cx="48" cy="48" r="44"></circle>
</svg>
</div>
<div class="loader__icon">
<!-- Icone de documento -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
</svg>
</div>
</div>
<div class="loader__content">
<h3 class="loader__title">Gerando documento...</h3>
<p class="loader__subtitle">Validando e-mail</p>
</div>
</div>Exemplo 2: Upload de Arquivo
html
<div class="loader loader--info">
<div class="loader__spinner">
<div class="loader__ring">
<svg viewBox="0 0 96 96">
<circle class="loader__ring-track" cx="48" cy="48" r="44"></circle>
<circle class="loader__ring-arc" cx="48" cy="48" r="44"></circle>
</svg>
</div>
<div class="loader__icon">
<!-- Icone de upload -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>
</div>
</div>
<div class="loader__content">
<h3 class="loader__title">Enviando arquivo...</h3>
<p class="loader__subtitle">relatorio-2026.pdf</p>
</div>
</div>Exemplo 3: Processamento com Progresso
html
<div class="loader loader--progress">
<div class="loader__spinner">
<div class="loader__ring">
<svg viewBox="0 0 96 96">
<circle class="loader__ring-track" cx="48" cy="48" r="44"></circle>
<circle class="loader__ring-arc" cx="48" cy="48" r="44"
id="progress-arc" style="stroke-dashoffset: 138.23"></circle>
</svg>
</div>
<div class="loader__icon">
<!-- Icone de processamento -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<polyline points="12 6 12 12 16 14"/>
</svg>
</div>
</div>
<div class="loader__content">
<h3 class="loader__title">Processando dados...</h3>
<p class="loader__subtitle" id="progress-text">50% concluido</p>
</div>
</div>
<script>
function updateProgress(percent) {
const arc = document.getElementById('progress-arc');
const text = document.getElementById('progress-text');
const circumference = 276.46;
const offset = ((100 - percent) / 100) * circumference;
arc.style.strokeDashoffset = offset;
text.textContent = percent + '% concluido';
}
</script>Icones Sugeridos
Documento
html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
</svg>Upload
html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>Download
html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>Relogio/Processamento
html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<polyline points="12 6 12 12 16 14"/>
</svg>Email
html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
<polyline points="22,6 12,13 2,6"/>
</svg>Boas Praticas
- Use titulos descritivos: Seja claro sobre o que esta acontecendo
- Atualize o subtitulo: Mostre progresso ou etapas quando possivel
- Escolha icones apropriados: O icone deve refletir a acao
- Use variantes de cor: Diferencie tipos de operacoes
- Considere o tempo: Loaders muito longos frustram usuarios
Versao: 1.0.0 Data: 02/02/2026 CSS: /public/css/design-system/components/loader.cssExemplo: /public/css/design-system/examples/loader.html