Navigasi & Struktur
Stepper (Indikator Tahapan Formulir)
Penanda langkah berurutan untuk memandu warga menyelesaikan formulir permohonan layanan yang panjang.
Stepper (.mjl-stepper) memecah formulir permohonan perizinan atau kependudukan yang rumit menjadi beberapa tahap logis yang mudah dipahami warga.
Di layar lebar stepper tampil horizontal; di bawah 768px otomatis berubah vertikal agar judul tahap tidak terpotong di HP.
1. Pratinjau Stepper 4 Tahap
Pratinjau Alur Permohonan
-
Selesai: Data Diri NIK & KK
-
Tahap saat ini: Unggah Berkas Foto dokumen
-
Belum dimulai: Konfirmasi Tinjau ulang
-
Belum dimulai: Selesai Nomor tiket
2. Tahap Terakhir Sedang Berjalan
Stepper 3 Tahap
-
Selesai: Isi Data Data pemohon
-
Selesai: Unggah Berkas KTP & KK
-
Tahap saat ini: Konfirmasi Tinjau ulang
3. Status Tahap
| Class | Tampilan | Kapan dipakai |
|---|---|---|
mjl-stepper__item--completed | Lingkaran biru penuh berisi centang, garis penghubung biru | Tahap yang sudah selesai |
mjl-stepper__item--current | Lingkaran bergaris biru dengan cincin fokus | Tahap yang sedang diisi warga (tambahkan aria-current="step") |
| (tanpa modifier) | Lingkaran abu-abu | Tahap yang belum dimulai |
Penggunaan di Berbagai Teknologi
Salin contoh sesuai teknologi proyek Anda. Semua versi memakai class dari @majalengka/css. Komponen siap pakai tersedia di @majalengka/vue; untuk React, Angular, Laravel, dan PHP, contoh di bawah sudah berupa pembungkus kecil yang bisa langsung disalin ke proyek.
<ol class="mjl-stepper" aria-label="Tahapan pengajuan">
<li class="mjl-stepper__item mjl-stepper__item--completed">
<span class="mjl-stepper__indicator" aria-hidden="true">✓</span>
<div class="mjl-stepper__content">
<span class="mjl-stepper__title"><span class="sr-only">Selesai: </span>Data Diri</span>
</div>
</li>
<li class="mjl-stepper__item mjl-stepper__item--current" aria-current="step">
<span class="mjl-stepper__indicator" aria-hidden="true">2</span>
<div class="mjl-stepper__content">
<span class="mjl-stepper__title"><span class="sr-only">Tahap saat ini: </span>Unggah Berkas</span>
</div>
</li>
<li class="mjl-stepper__item">
<span class="mjl-stepper__indicator" aria-hidden="true">3</span>
<div class="mjl-stepper__content">
<span class="mjl-stepper__title"><span class="sr-only">Belum dimulai: </span>Konfirmasi</span>
</div>
</li>
</ol>
<script setup lang="ts">
import { ref } from 'vue';
import { MjlStepper } from '@majalengka/vue';
const tahap = ref(1);
const langkah = [
{ id: 'data', title: 'Data Diri', desc: 'NIK & KK' },
{ id: 'berkas', title: 'Unggah Berkas', desc: 'Foto dokumen' },
{ id: 'konfirmasi', title: 'Konfirmasi', desc: 'Tinjau ulang' },
];
</script>
<template>
<MjlStepper :steps="langkah" :current-step-index="tahap" />
</template>
const STATUS = { completed: 'Selesai: ', current: 'Tahap saat ini: ', upcoming: 'Belum dimulai: ' } as const;
export function MjlStepper({ steps, current }: { steps: { title: string; desc?: string }[]; current: number }) {
return (
<ol className="mjl-stepper" aria-label="Tahapan pengajuan">
{steps.map((s, i) => {
const st = i < current ? 'completed' : i === current ? 'current' : 'upcoming';
return (
<li key={s.title} className={`mjl-stepper__item ${st !== 'upcoming' ? `mjl-stepper__item--${st}` : ''}`} aria-current={st === 'current' ? 'step' : undefined}>
<span className="mjl-stepper__indicator" aria-hidden="true">{st === 'completed' ? '✓' : i + 1}</span>
<div className="mjl-stepper__content">
<span className="mjl-stepper__title"><span className="sr-only">{STATUS[st]}</span>{s.title}</span>
{s.desc && <span className="mjl-stepper__desc">{s.desc}</span>}
</div>
</li>
);
})}
</ol>
);
}
import { Component, input } from '@angular/core';
@Component({
selector: 'mjl-stepper',
standalone: true,
template: `
<ol class="mjl-stepper" aria-label="Tahapan pengajuan">
@for (s of steps(); track s.title; let i = $index) {
<li class="mjl-stepper__item" [class.mjl-stepper__item--completed]="i < current()"
[class.mjl-stepper__item--current]="i === current()" [attr.aria-current]="i === current() ? 'step' : null">
<span class="mjl-stepper__indicator" aria-hidden="true">{{ i < current() ? '✓' : i + 1 }}</span>
<div class="mjl-stepper__content">
<span class="mjl-stepper__title">
<span class="sr-only">{{ i < current() ? 'Selesai: ' : i === current() ? 'Tahap saat ini: ' : 'Belum dimulai: ' }}</span>{{ s.title }}
</span>
</div>
</li>
}
</ol>
`,
})
export class MjlStepper {
steps = input.required<{ title: string }[]>();
current = input(0);
}
{{-- resources/views/components/mjl/stepper.blade.php --}}
@props(['steps', 'current' => 0])
<ol class="mjl-stepper" aria-label="Tahapan pengajuan">
@foreach ($steps as $i => $judul)
<li @class(['mjl-stepper__item', 'mjl-stepper__item--completed' => $i < $current, 'mjl-stepper__item--current' => $i === $current])
@if ($i === $current) aria-current="step" @endif>
<span class="mjl-stepper__indicator" aria-hidden="true">{{ $i < $current ? '✓' : $i + 1 }}</span>
<div class="mjl-stepper__content">
<span class="mjl-stepper__title">
<span class="sr-only">{{ $i < $current ? 'Selesai: ' : ($i === $current ? 'Tahap saat ini: ' : 'Belum dimulai: ') }}</span>{{ $judul }}
</span>
</div>
</li>
@endforeach
</ol>
{{-- Pemakaian --}}
<x-mjl.stepper :steps="['Data Diri', 'Unggah Berkas', 'Konfirmasi']" :current="1" />
<?php $langkah = ['Data Diri', 'Unggah Berkas', 'Konfirmasi']; $sekarang = 1; ?>
<ol class="mjl-stepper" aria-label="Tahapan pengajuan">
<?php foreach ($langkah as $i => $judul):
$status = $i < $sekarang ? 'completed' : ($i === $sekarang ? 'current' : 'upcoming'); ?>
<li class="mjl-stepper__item<?= $status !== 'upcoming' ? " mjl-stepper__item--$status" : '' ?>"<?= $status === 'current' ? ' aria-current="step"' : '' ?>>
<span class="mjl-stepper__indicator" aria-hidden="true"><?= $status === 'completed' ? '✓' : $i + 1 ?></span>
<div class="mjl-stepper__content">
<span class="mjl-stepper__title"><?= htmlspecialchars($judul, ENT_QUOTES, 'UTF-8') ?></span>
</div>
</li>
<?php endforeach; ?>
</ol>
4. Kaidah Aksesibilitas
- Pakai
<ol>: urutan tahap ikut terbaca oleh pembaca layar ("daftar, 4 item"). aria-current="step"pada tahap yang sedang berjalan.- Status tidak boleh hanya lewat warna (WCAG 1.4.1): sertakan teks tersembunyi seperti
<span class="sr-only">Selesai: </span>di judul tahap. Komponen VueMjlSteppersudah melakukannya otomatis. - Indikator bersifat dekoratif (
aria-hidden="true"), karena nomor tahap sudah tersirat dari urutan daftar.