Button (Tombol)
Tombol (.mjl-btn) adalah elemen interaktif utama yang digunakan warga dan petugas untuk mengeksekusi tindakan — seperti mengirim permohonan, mengunduh bukti tanda terima, atau membuka modal konfirmasi.
Semua tombol di Majalengka Design System memenuhi standar WCAG 2.1 Level AA dengan ukuran sentuh minimum 44×44px pada perangkat seluler.
Pratinjau Langsung (Live Demo)
Coba seluruh variasi, ukuran, status interaktif, dan efek loading secara langsung di bawah ini:
1. Variasi Gaya (Variants)
Lima varian tombol resmi yang disesuaikan dengan hierarki aksi antarmuka.
2. Ukuran Tombol (Sizes)
Target sentuh minimum 44px (WCAG 2.1 AA) pada ukuran standar.
3. Status Interaktif (Interactive States)
Klik tombol "Klik untuk Simulasi Loading" untuk melihat efek spinner.
4. Tombol dengan Ikon
Kombinasi ikon tajam untuk mempercepat identifikasi visual.
1. Variasi Gaya (Variants)
Tersedia 5 variasi tombol sesuai dengan hierarki aksi antarmuka:
| Variasi | Kelas CSS | Rekomendasi Penggunaan |
|---|---|---|
| Primary | .mjl-btn--primary | Hanya satu per tampilan utama: Kirim formulir, Lanjut tahap berikutnya. |
| Secondary | .mjl-btn--secondary | Aksi pendukung: Simpan draf, Cetak pratinjau, Filter tabel. |
| Outline | .mjl-btn--outline | Aksi alternatif dengan penekanan visual sedang: Kembali, Batal. |
| Ghost | .mjl-btn--ghost | Aksi rendah penekanan di dalam tabel atau header kartu: Sunting, Salin. |
| Danger | .mjl-btn--danger | Tindakan destruktif tidak dapat diulang: Hapus akun, Batalkan izin. |
2. Ukuran Tombol & Standar Sentuh
!IMPORTANT Jangan gunakan ukuran
.mjl-btn--smuntuk alur utama pada perangkat seluler. Standar aksesibilitas kependudukan mewajibkan target sentuh fisik minimum 44px agar mudah ditekan oleh jempol warga lansia.
3. Status Interaktif (Interactive States)
Tombol merespons status visual pengguna: Normal, Hover, Fokus Keyboard, Loading, dan Disabled.
4. Tombol dengan Ikon
Ikon memperjelas maksud tombol secara visual sebelum membaca teks:
5. Integrasi Vue 3 (@majalengka/vue)
Jika menggunakan tumpukan Vue 3 atau Nuxt, impor komponen <MjlButton>:
<script setup lang="ts">
import { MjlButton } from '@majalengka/vue';
import { ref } from 'vue';
const isSubmitting = ref(false);
async function handleSubmit() {
isSubmitting.value = true;
await submitRegistration();
isSubmitting.value = false;
}
</script>
<template>
<div class="flex gap-3">
<MjlButton
variant="primary"
size="md"
:loading="isSubmitting"
@click="handleSubmit"
>
Kirim Permohonan
</MjlButton>
<MjlButton variant="outline" to="/layanan">
Batal
</MjlButton>
</div>
</template>
Properti Komponen (Props API)
| Properti | Tipe | Nilai Bawaan | Deskripsi |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'primary' | Variasi gaya visual |
size | 'sm' | 'md' | 'lg' | 'md' | Ukuran tombol fisik |
loading | boolean | false | Menampilkan spinner dan menonaktifkan klik |
disabled | boolean | false | Menonaktifkan interaksi tombol |
type | 'button' | 'submit' | 'reset' | 'button' | Atribut tipe HTML |
to | string | undefined | Jika diisi, tombol dirender sebagai tautan semantic (<a>) |
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.
<button type="button" class="mjl-btn mjl-btn--primary mjl-btn--md">Kirim Permohonan</button>
<button type="button" class="mjl-btn mjl-btn--outline mjl-btn--md">Simpan Draf</button>
<a href="/layanan" class="mjl-btn mjl-btn--ghost mjl-btn--md">Lihat Layanan</a>
<script setup lang="ts">
import { MjlButton } from '@majalengka/vue';
function kirim() {
// proses formulir
}
</script>
<template>
<MjlButton variant="primary" @click="kirim">Kirim Permohonan</MjlButton>
<MjlButton variant="outline">Simpan Draf</MjlButton>
<MjlButton variant="ghost" href="/layanan">Lihat Layanan</MjlButton>
<MjlButton variant="primary" loading>Menyimpan...</MjlButton>
</template>
import type { ButtonHTMLAttributes } from 'react';
type Variant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
interface MjlButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: Variant;
size?: 'sm' | 'md' | 'lg';
}
export function MjlButton({ variant = 'primary', size = 'md', className = '', type = 'button', ...rest }: MjlButtonProps) {
return <button type={type} className={`mjl-btn mjl-btn--${variant} mjl-btn--${size} ${className}`} {...rest} />;
}
// Pemakaian
export function Contoh() {
return (
<>
<MjlButton onClick={() => console.log('kirim')}>Kirim Permohonan</MjlButton>
<MjlButton variant="outline">Simpan Draf</MjlButton>
</>
);
}
import { Component, input } from '@angular/core';
@Component({
selector: 'button[mjlButton]',
standalone: true,
host: { '[class]': '"mjl-btn mjl-btn--" + variant() + " mjl-btn--" + size()' },
template: '<ng-content />',
})
export class MjlButton {
variant = input<'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'>('primary');
size = input<'sm' | 'md' | 'lg'>('md');
}
// Pemakaian (imports: [MjlButton]):
// <button mjlButton type="button" (click)="kirim()">Kirim Permohonan</button>
// <button mjlButton variant="outline" type="button">Simpan Draf</button>
{{-- resources/views/components/mjl/button.blade.php --}}
@props(['variant' => 'primary', 'size' => 'md', 'href' => null])
@if ($href)
<a href="{{ $href }}" {{ $attributes->class(["mjl-btn mjl-btn--{$variant} mjl-btn--{$size}"]) }}>{{ $slot }}</a>
@else
<button {{ $attributes->merge(['type' => 'button'])->class(["mjl-btn mjl-btn--{$variant} mjl-btn--{$size}"]) }}>{{ $slot }}</button>
@endif
{{-- Pemakaian --}}
<x-mjl.button type="submit">Kirim Permohonan</x-mjl.button>
<x-mjl.button variant="ghost" :href="route('layanan.index')">Lihat Layanan</x-mjl.button>
<?php
function mjl_button(string $label, string $variant = 'primary', string $size = 'md', string $type = 'button'): string
{
$label = htmlspecialchars($label, ENT_QUOTES, 'UTF-8');
return "<button type=\"{$type}\" class=\"mjl-btn mjl-btn--{$variant} mjl-btn--{$size}\">{$label}</button>";
}
?>
<form method="post" action="/permohonan">
<?= mjl_button('Kirim Permohonan', 'primary', 'md', 'submit') ?>
<?= mjl_button('Simpan Draf', 'outline') ?>
</form>
6. Kaidah Aksesibilitas (WCAG 2.1 AA)
- Target Sentuh Minimum: Tombol
mdmemiliki tinggi fisik44px, mencukupi Success Criterion 2.5.5. - Rasio Kontras: Teks putih pada Biru Majalengka 700 (
#0014A8) menghasilkan kontras 10.5:1 (jauh melampaui ambang batas 4.5:1). - Indikator Fokus: Menggunakan cincin fokus ganda (
outline: 3px solid var(--mjl-color-primary-300)) yang terlihat jelas saat navigasi menggunakan tombolTab. - Screen Reader: Jika tombol hanya berisi ikon tanpa teks, wajib mencantumkan atribut
aria-label="Nama Aksi"agar pembaca layar dapat membacakannya.