Components · · 2 min read
Company-profile component: testimonial card & JS-free FAQ accordion
A FAQ accordion using the browser's built-in <details> element (still indexed by Google while collapsed) and a testimonial card with initial avatars + figure/blockquote semantics — code and preview side by side.
<figure class="quote">
<blockquote>
Fit-out 800m² selesai 3 hari lebih cepat dari jadwal. Laporan progres
masuk tiap Jumat tanpa diminta.
</blockquote>
<figcaption class="quote__by">
<!-- Inisial: pengganti foto yang tidak pernah gagal dimuat -->
<span class="avatar" aria-hidden="true">RS</span>
<span>
<b>Rina Susanti</b>
<small>GM Operasional, PT Maju Bersama</small>
</span>
</figcaption>
</figure>
<!-- Accordion tanpa JavaScript: <details> sudah bisa buka-tutup sendiri -->
<div class="faq">
<details open>
<summary>Berapa lama pengerjaan fit-out kantor?<span class="faq__x">+</span></summary>
<p>6–10 minggu untuk 500–1000m², tergantung kompleksitas MEP dan approval gedung.</p>
</details>
<details>
<summary>Apakah termasuk perizinan gedung?<span class="faq__x">+</span></summary>
<p>Ya. Pengurusan izin kerja dan koordinasi dengan building management masuk scope.</p>
</details>
<details>
<summary>Bagaimana skema pembayarannya?<span class="faq__x">+</span></summary>
<p>Termin: 40% mulai, 40% progres 50%, 20% serah terima setelah punch list beres.</p>
</details>
</div>.quote {
margin: 0 0 22px;
border: 1px solid #e4e4e7;
padding: 18px;
}
.quote blockquote {
margin: 0;
font-size: 14px;
line-height: 1.65;
}
.quote__by {
margin-top: 14px;
display: flex;
align-items: center;
gap: 10px;
}
.avatar {
width: 36px;
height: 36px;
flex: none;
border-radius: 999px;
background: #f0fdfa;
color: #0f766e;
display: grid;
place-items: center;
font-size: 12px;
font-weight: 600;
}
.quote__by b { display: block; font-size: 13px; }
.quote__by small { display: block; font-size: 12px; color: #71717a; }
.faq { border-top: 1px solid #e4e4e7; }
.faq details { border-bottom: 1px solid #e4e4e7; }
.faq summary {
list-style: none; /* buang segitiga bawaan */
cursor: pointer;
padding: 13px 0;
font-size: 14px;
font-weight: 600;
display: flex;
justify-content: space-between;
gap: 12px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq__x {
color: #0d9488;
transition: transform 0.2s ease;
}
.faq details[open] .faq__x { transform: rotate(45deg); }
.faq p {
margin: 0 0 14px;
font-size: 13px;
line-height: 1.7;
color: #52525b;
}Preview
These two components appear in almost every company profile I build — and both can be made without a single line of JavaScript. Open and close the FAQ in the preview panel: that’s pure HTML.
Accordions with <details>: a browser feature, not a library
Most tutorials teach accordions with a click listener plus class toggling. HTML already has the element:
<details open>
<summary>How long does the work take?<span class="faq__x">+</span></summary>
<p>6–10 weeks for 500–1000m²...</p>
</details>
What you get for free: open/close, keyboard navigation (Tab + Enter), an open state you can style, and — most important for a company profile — the content stays in the HTML, so Google’s crawler reads it even while collapsed. A JavaScript accordion that hides content with display:none is also indexed, but one that fetches its content on click is not.
Two lines of CSS remove the browser’s default triangle:
.faq summary { list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
Then the + icon rotates 45° into a × when open, purely through the [open] selector:
.faq details[open] .faq__x { transform: rotate(45deg); }
One important note: if you add FAQPage JSON-LD (see the SEO & GEO build note), the <details> content must match the schema exactly — Google validates that the two agree.
Testimonials: initial avatars beat photos
Client photos are often unavailable, badly cropped, or fail to load. Initial avatars (RS, AN) always render perfectly, cost zero network requests, and never break:
.avatar {
width: 36px; height: 36px;
border-radius: 999px;
display: grid; place-items: center; /* two-line centering */
}
What actually drives credibility isn’t the photo but complete attribution: full name + role + company. Anonymous testimonials (“Mr. A, Jakarta”) actively lower trust — readers assume they’re invented.
Correct semantics
Note the elements: <figure> + <blockquote> + <figcaption>. This isn’t cosmetic — that combination tells machines (and screen-reader users) that the text is a quotation with a specific source. A plain <div class="quote"> communicates nothing.
Lessons
- Before writing a listener, check whether HTML already has the element —
<details>,<dialog>, and<datalist>are often a surprise. - Hidden content must still exist in the initial HTML if you care about SEO.
- Testimonial credibility comes from complete attribution, not from a photo.
Want something like this built for your business?