Order 1 Ganda: Saat Sidebar Riwayat Chat Menghilang di lg
Sidebar riwayat chat hilang di breakpoint lg: tie-break order CSS dan elemen details yang dipaksa jadi wadah flex, dua akar masalah satu commit.
Ringkasan
Sidebar chat menghilang di breakpoint lg karena dua bug dari refactor accordion mobile. Pertama, nilai order yang sama membuat wrapper tengah menang tie-break urutan sumber sehingga sidebar terdorong keluar viewport; solusinya cukup tambah lg:order-2. Kedua, elemen details tidak cocok jadi wadah flex di Chromium, jadi accordion diganti state React biasa dengan tombol aria-expanded dan div.
Sore itu saya buka halaman chat di lebar layar 1024 piksel, dan kolom riwayat yang biasanya nangkring di kiri hilang. Wrapper tengah melebar sendirian, seolah kolom itu tidak pernah ada. Tidak ada error di konsol, tidak ada elemen yang hilang dari DOM; dia cuma tidak di tempatnya.
Dugaan pertama saya mengarah ke ukuran: mungkin lebar kolom 320px bentrok dengan sisa ruang, atau ada overflow yang memotongnya. Dua-duanya meleset. Akar masalahnya ada dua, dan keduanya lahir dari refactor accordion mobile yang saya lakukan sebelumnya.
Order sama, urutan sumber jadi hakim
Wrapper tengah cuma saya beri xl:order-2, sedangkan sidebar bernilai satu dari class order-1. Artinya di breakpoint lg dua item flex itu sama-sama bernilai 1. Dokumentasi MDN untuk properti order menjelaskan item diurutkan dari nilai order menaik, lalu dari urutan sumber; nilai default-nya 0 [5]. Untuk nilai sama persis, panduan Ordering flex items menyebut kelompok itu ditata menurut urutan sumber [6].
Wrapper tengah saya tulis lebih dulu di JSX, jadi dia menang tie-break. Di layar yang lebar menjadi lg tapi belum xl, wrapper melebar penuh dan sidebar terdorong ke kanan sampai keluar viewport. Perbaikannya satu class:
// sebelum: hanya xl yang punya urutan eksplisit
<div className="order-1 flex min-w-0 flex-1 flex-col ... xl:order-2">
// sesudah: lg ikut eksplisit
<div className="order-1 flex min-w-0 flex-1 flex-col ... lg:order-2 xl:order-2">
Satu catatan yang saya simpan dari halaman yang sama: order hanya mengubah urutan visual, bukan urutan logika atau tab [5]. Jadi memindah kolom lewat order aman untuk mata, tapi tidak menggantikan struktur DOM yang masuk akal.
details dipakai di luar peruntukannya
Akar kedua lebih menarik. Accordion mobile di commit sebelumnya saya bangun dari elemen details ber-class lg:contents, supaya di desktop "nakinya" menghilang dan anak-anaknya ikut tata letak kolom. Ternyata di Chromium anak-anak di dalam details mengabaikan penentuan ukuran flex. Ini temuan empiris saya saat debugging, dan commit mencatatnya polos: a details cannot act as a proper flex container in Chromium.
Kontrak resminya memang begitu adanya: details adalah disclosure widget yang isinya baru terlihat ketika atribut open menyertainya [7]. Untuk accordion murni dia pilihan yang sah; masalah muncul justru saat saya memaksanya jadi wadah tata letak desktop. Solusinya keluar dari details sepenuhnya: state React biasa dengan tombol bertanda aria-expanded di mobile, dan pembungkus div yang berganti class:
<button onClick={() => setHistoryOpen((v) => !v)}
aria-expanded={historyOpen}
className="... lg:hidden">
{ta("historyTitle")}
</button>
<div className={cn("min-h-0 flex-1 flex-col lg:flex",
historyOpen ? "flex" : "hidden")}>
<ChatThreadPanel ... />
</div>
Kolomnya juga saya kasih tinggi pasti lg:h-[85vh] supaya timeline bisa mengisi ruang dan menggulir di dalam kolomnya sendiri, bukan menyeret tinggi halaman.
Dua jam berkutat dengan class mengajarikan satu hal: sebelum menyalahkan angka seperti 320px, cek dulu kontrak kecil yang jarang dipikirkan, dari tie-break order sampai elemen yang dipakai di luar peruntukannya. Kebetulan di sidebar yang sama saya juga pernah memindah saklar mode chat ke puncak sidebar, dan itu menyisakan pelajaran tata letak yang serumpun.
Sumber
- [5] MDN: order, diakses 2026-09-08
- [6] MDN: Ordering flex items, diakses 2026-09-08
- [7] MDN: elemen details, diakses 2026-09-08