Accordion (Daftar Lipat / FAQ)
Accordion (.mjl-accordion) memungkinkan warga melihat ringkasan topik pertanyaan umum dan membuka detailnya tanpa membuat halaman menjadi terlalu panjang.
Dibangun di atas elemen bawaan <details> dan <summary>, jadi tetap bisa dibuka-tutup tanpa JavaScript. Di browser modern (Chrome/Edge 131+), butir membuka dan menutup dengan animasi halus; browser lain tetap berfungsi, hanya tanpa animasi.
1. Pratinjau Accordion Tanya Jawab (FAQ)
Berapa biaya pengurusan KTP dan Kartu Keluarga di Majalengka?
Seluruh pengurusan dokumen kependudukan (KTP, KK, Akta Kelahiran, KIA) di Kabupaten Majalengka adalah 100% GRATIS. Jika ada pungutan, laporkan ke Satgas Saber Pungli.
Berapa lama waktu penerbitan dokumen setelah berkas diverifikasi?
Verifikasi berkas memakan waktu maksimal 1×24 jam kerja. Dokumen digital (PDF bertanda tangan elektronik) dapat langsung diunduh dari akun Anda.
Bagaimana jika NIK saya tidak terbaca saat mendaftar?
Lakukan sinkronisasi data NIK melalui layanan WhatsApp Dukcapil atau datangi kantor kecamatan terdekat pada hari kerja.
2. Hanya Satu Butir Terbuka
Beri semua <details> atribut name yang sama. Browser akan otomatis menutup butir lain saat satu butir dibuka, tanpa JavaScript.
Berapa biaya pengurusan KTP dan Kartu Keluarga di Majalengka?
Seluruh pengurusan dokumen kependudukan (KTP, KK, Akta Kelahiran, KIA) di Kabupaten Majalengka adalah 100% GRATIS. Jika ada pungutan, laporkan ke Satgas Saber Pungli.
Berapa lama waktu penerbitan dokumen setelah berkas diverifikasi?
Verifikasi berkas memakan waktu maksimal 1×24 jam kerja. Dokumen digital (PDF bertanda tangan elektronik) dapat langsung diunduh dari akun Anda.
Bagaimana jika NIK saya tidak terbaca saat mendaftar?
Lakukan sinkronisasi data NIK melalui layanan WhatsApp Dukcapil atau datangi kantor kecamatan terdekat pada hari kerja.
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.
<div class="mjl-accordion">
<details class="mjl-accordion__item" name="faq" open>
<summary class="mjl-accordion__summary">
Berapa biaya pengurusan KTP?
<svg class="mjl-accordion__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
</summary>
<div class="mjl-accordion__content"><p>Gratis, tidak dipungut biaya apa pun.</p></div>
</details>
<details class="mjl-accordion__item" name="faq">
<summary class="mjl-accordion__summary">
Berapa lama prosesnya?
<svg class="mjl-accordion__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
</summary>
<div class="mjl-accordion__content"><p>Maksimal 1×24 jam kerja setelah berkas lengkap.</p></div>
</details>
</div>
<script setup lang="ts">
import { MjlAccordion } from '@majalengka/vue';
const faq = [
{ title: 'Berapa biaya pengurusan KTP?', content: 'Gratis, tidak dipungut biaya apa pun.', open: true },
{ title: 'Berapa lama prosesnya?', content: 'Maksimal 1×24 jam kerja setelah berkas lengkap.' },
];
</script>
<template>
<MjlAccordion :items="faq" exclusive />
</template>
const Chevron = () => (
<svg className="mjl-accordion__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} aria-hidden="true">
<path d="m6 9 6 6 6-6" />
</svg>
);
export function MjlAccordion({ items, name }: { items: { title: string; content: string }[]; name?: string }) {
return (
<div className="mjl-accordion">
{items.map((item, i) => (
<details key={item.title} className="mjl-accordion__item" name={name} open={i === 0}>
<summary className="mjl-accordion__summary">{item.title}<Chevron /></summary>
<div className="mjl-accordion__content"><p>{item.content}</p></div>
</details>
))}
</div>
);
}
import { Component, input } from '@angular/core';
@Component({
selector: 'mjl-accordion',
standalone: true,
template: `
<div class="mjl-accordion">
@for (item of items(); track item.title) {
<details class="mjl-accordion__item" [attr.name]="name()">
<summary class="mjl-accordion__summary">
{{ item.title }}
<svg class="mjl-accordion__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
</summary>
<div class="mjl-accordion__content"><p>{{ item.content }}</p></div>
</details>
}
</div>
`,
})
export class MjlAccordion {
items = input.required<{ title: string; content: string }[]>();
name = input<string>();
}
<div class="mjl-accordion">
@foreach ($faq as $item)
<details class="mjl-accordion__item" name="faq" @if ($loop->first) open @endif>
<summary class="mjl-accordion__summary">
{{ $item->pertanyaan }}
<svg class="mjl-accordion__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
</summary>
<div class="mjl-accordion__content">{!! Str::markdown($item->jawaban) !!}</div>
</details>
@endforeach
</div>
<div class="mjl-accordion">
<?php foreach ($faq as $i => $item): ?>
<details class="mjl-accordion__item" name="faq" <?= $i === 0 ? 'open' : '' ?>>
<summary class="mjl-accordion__summary">
<?= htmlspecialchars($item['tanya']) ?>
<svg class="mjl-accordion__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
</summary>
<div class="mjl-accordion__content"><p><?= htmlspecialchars($item['jawab']) ?></p></div>
</details>
<?php endforeach; ?>
</div>
3. Kaidah Aksesibilitas
- Jangan ganti
<summary>dengan<div>:<summary>sudah bisa difokus, diaktifkan dengan Enter/Spasi, dan mengumumkan status terbuka/tertutup. - Ikon chevron dekoratif: beri
aria-hidden="true"; status sudah diumumkan oleh elemen<details>. - Gerak minimal: animasi otomatis dimatikan bila pengguna mengaktifkan reduce motion di sistem operasinya.