Um componente de passo de progresso é uma ferramenta adicionada aos formulários para agilizar a interação do usuário, dividindo as tarefas em etapas gerenciáveis. Ele oferece uma navegação direta, acompanha visualmente o progresso e aprimora a experiência do usuário.
Este tutorial cobrirá a construção de um componente de passo de progresso com HTML, CSS e JavaScript.
Estrutura HTML
A estrutura HTML será composta pelos seguintes elementos:
- Quatro elementos div circulares para representar as 4 etapas do processo de navegação.
- Duas barras horizontais.
- Anterior e Próximo botões para navegar entre as etapas.
- Um componente de mensagem para exibir quaisquer mensagens informativas.
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
Step 1
|
8 |
class="fa-solid fa-check">
|
9 |
|
10 |
|
11 |
Step 2
|
12 |
class="fa-solid fa-check">
|
13 |
|
14 |
|
15 |
Step 3
|
16 |
class="fa-solid fa-check">
|
17 |
|
18 |
|
19 |
Step 4
|
20 |
class="fa-solid fa-check">
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
class="fa-solid fa-check">
|
32 |
Your details have been submitted
|
33 |
|
Estilizando com CSS
Vamos começar aplicando os seguintes estilos ao corpo para garantir que o conteúdo fique centralizado.
1 |
body { |
2 |
min-height: 100vh; |
3 |
background-color: rgb(231, 233, 242); |
4 |
display: flex; |
5 |
justify-content: center; |
6 |
align-items: center; |
7 |
font-family: "Roboto", sans-serif; |
8 |
}
|
Então, teremos um contêiner para armazenar todos os nossos elementos:
1 |
.container { |
2 |
width: 700px; |
3 |
height: 300px; |
4 |
}
|
Teremos outro contêiner que usa Flexbox para garantir que os círculos que representam as diferentes etapas sejam espaçados uniformemente ao longo do eixo horizontal.
1 |
.progress-container { |
2 |
width: 100%; |
3 |
display: flex; |
4 |
justify-content: space-between; |
5 |
margin: 50px auto; |
6 |
position: relative; |
7 |
}
|
Vamos tornar os elementos div que representam as etapas circulares, fornecendo dimensões iguais e um raio de borda.
1 |
.circle { |
2 |
width: 50px; |
3 |
height: 50px; |
4 |
background-color: white; |
5 |
border-radius: 50%; |
6 |
position: relative; |
7 |
}
|
Também precisamos garantir que os ícones estejam posicionados no centro dos círculos e que a extensão esteja diretamente abaixo do círculo correspondente. Por padrão, todos os ícones ficarão invisíveis.
1 |
.circle span { |
2 |
position: absolute; |
3 |
top: 150%; |
4 |
left: 9%; |
5 |
color: #141d0d; |
6 |
|
7 |
}
|
8 |
|
9 |
.circle i { |
10 |
position: absolute; |
11 |
top: 35%; |
12 |
left: 35%; |
13 |
display: none; |
14 |
|
15 |
}
|
Por padrão, o primeiro círculo terá o ícone visível e também terá um fundo verde.
1 |
.circle.active i { |
2 |
display: block; |
3 |
}
|
4 |
|
5 |
.active { |
6 |
display: block; |
7 |
background-color: #43880f; |
8 |
}
|
Os botões terão os seguintes estilos.
1 |
.buttons { |
2 |
display: flex; |
3 |
justify-content: center; |
4 |
align-items: center; |
5 |
position: relative; |
6 |
} |
7 |
button { |
8 |
color: white; |
9 |
width: 100px; |
10 |
padding: 10px 20px; |
11 |
margin: 20px auto; |
12 |
border-radius: 3px; |
13 |
background-color: #43880f; |
14 |
border: none; |
15 |
} |
16 |
.next { |
17 |
color: white; |
18 |
/* background-color: rgb(87, 87, 202); */ |
19 |
} |
20 |
.submit { |
21 |
display: none; |
22 |
} |
23 |
button:disabled { |
24 |
cursor: not-allowed; |
25 |
background-color: gray; |
26 |
} |
Por padrão, o botão enviar ficará oculto. Ele será exibido quando um usuário concluir todas as etapas necessárias.
As barras horizontais (barra de progresso e barra de status) serão posicionadas atrás dos círculos. A primeira barra (.progress-bar
) ficará inativo, enquanto a segunda barra (.status-bar
) a duração será animada dependendo do progresso do usuário.
1 |
.progress-bar { |
2 |
width: 99%; |
3 |
height: 5px; |
4 |
background-color: grey; |
5 |
position: absolute; |
6 |
top: 50%; |
7 |
left: 0; |
8 |
|
9 |
z-index: -1; |
10 |
}
|
11 |
.status-bar { |
12 |
width: 100%; |
13 |
height: 5px; |
14 |
background-color: transparent; |
15 |
position: absolute; |
16 |
top: 50%; |
17 |
left: 0; |
18 |
z-index: -1; |
19 |
}
|
20 |
.animate { |
21 |
animation: fill 0.5s ease-in-out 0.4s forwards; |
22 |
}
|
23 |
|
24 |
@keyframes fill { |
25 |
100% { |
26 |
box-shadow: inset 0px 0px 0px 30px #43880f; |
27 |
}
|
28 |
}
|
Finalmente, o componente de mensagem terá os seguintes estilos e ficará oculto por padrão:
1 |
.message { |
2 |
width: 500px; |
3 |
height: 300px; |
4 |
border-radius: 5px; |
5 |
border: 2px solid; |
6 |
gap: 10px; |
7 |
display: block; |
8 |
text-align: center; |
9 |
padding: 100px 5px; |
10 |
display: none; |
11 |
}
|
12 |
|
13 |
.message i { |
14 |
margin-bottom: 50px; |
15 |
font-size: 25px; |
16 |
padding: 20px 20px; |
17 |
background-color: rgb(230, 111, 196); |
18 |
border-radius: 50%; |
19 |
animation: fillIcon 0.8s ease alternate; |
20 |
}
|
21 |
@keyframes fillIcon { |
22 |
0% { |
23 |
transform: scale(1); |
24 |
}
|
25 |
100% { |
26 |
transform: scale(1.2); |
27 |
}
|
28 |
}
|
Funcionalidade JavaScript
É hora de fazer isso funcionar! A primeira coisa que precisamos fazer é obter os elementos:
1 |
const progressBar = document.querySelectorAll(".progress-bar")[0]; |
2 |
const StatusBar = document.querySelectorAll(".status-bar")[0]; |
3 |
|
4 |
const circles = document.querySelectorAll(".circle"); |
5 |
const previousBtn = document.querySelector(".prev-btn"); |
6 |
const nextBtn = document.querySelector(".next-btn"); |
7 |
const submitBtn = document.querySelector(".submit"); |
8 |
const message = document.querySelector(".message"); |
Crie uma variável currentStepIndex
para acompanhar a etapa atualmente ativa em nosso componente de progresso.
1 |
let activeStepperIndex = 0; |
Em seguida, adicione um ouvinte de evento de clique no Próximo botão. Quando o botão é clicado, o currentStepIndex
aumentará em 1, movendo efetivamente o indicador de progresso para a próxima etapa.
1 |
nextBtn.addEventListener("click", function () { |
2 |
activeStepperIndex++; |
3 |
updateStepper(); |
4 |
});
|
O UpdateStepper()
função exibirá o ícone de verificação dependendo do novo valor do currentStepIndex
.
Defina uma função chamada updateStepper()
.
1 |
function updateStepper() { |
2 |
circles.forEach((circle, index) => { |
3 |
const textI = circle.querySelector("i"); |
4 |
if (index === activeStepperIndex) { |
5 |
previousBtn.style.backgroundColor = "grey"; |
6 |
textI.style.display = "block"; |
7 |
circle.classList.add("animate"); |
8 |
}
|
9 |
if (activeStepperIndex === 3) { |
10 |
nextBtn.style.display = "none"; |
11 |
submitBtn.style.display = "block"; |
12 |
}
|
13 |
});
|
14 |
// previousBtn.disabled = activeStepperIndex === 0;
|
15 |
}
|
Dentro da função, usaremos o built-in forEach()
método para iterar através de cada círculo
- Se o índice atual corresponder ao
activeStepperIndex
exibiremos o ícone de verificação no círculo correspondente e também animaremos o círculo. - Se o
activeStepperIndex
for o último, ocultaremos o botão Avançar e exibiremos o botão enviar.
Também queremos mostrar a representação visual da barra de status. Atualize o ouvinte de eventos para o Próximo botão, conforme mostrado abaixo.
1 |
nextBtn.addEventListener("click", function () { |
2 |
activeStepperIndex++; |
3 |
console.log(activeStepperIndex); |
4 |
const percentageWidth = |
5 |
(activeStepperIndex / (circles.length - 1)) * 100; |
6 |
StatusBar.style.width = percentageWidth + "%"; |
7 |
StatusBar.style.backgroundColor = "green"; |
8 |
|
9 |
|
10 |
updateStepper(); |
11 |
previousBtn.disabled = true; |
12 |
});
|
O visual adiciona um verde backgroundColor
para indicar o progresso feito através da barra. A largura é obtida dividindo-se activeStepperIndex
pelo número total de etapas (circles.length - 1
para ajustar a indexação baseada em zero) e multiplicar por 100 para obter o valor em porcentagem.
Por exemplo, se o passo estiver no passo 2, a largura será de 33,3% e assim por diante.
Por fim, quando o botão enviar estiver marcado, exibiremos o componente de mensagem ao usuário informando que seus dados foram enviados com sucesso.
Vamos adicionar um evento ouvinte para o botão enviar.
1 |
const message = document.querySelector(".message"); |
2 |
const container = document.querySelector(".container"); |
3 |
|
4 |
submitBtn.addEventListener("click", function () { |
5 |
message.style.display = "block"; |
6 |
container.style.display = "none"; |
7 |
});
|
8 |
});
|
Dentro da função, tornamos o componente de mensagem visível enquanto ocultamos o componente de passo.
Conclusão
Neste tutorial, aprendemos como construir um componente stepper sem nenhuma estrutura adicional. Felizmente, agora você pode criar componentes de passo ainda mais avançados.