FAQ Accordion Section
Секция частых вопросов (FAQ) с плавным аккордеоном и блоком обращения в службу поддержки.
Живое превью
Got Questions? We Have Answers
Everything you need to know about the Astro Components Kit, licensing, updates, and custom integrations.
Is this library compatible with Astro 5.x?
Yes! All components are built specifically for Astro 5.x and leverage Astro Content Collections, scoped styles, and zero-runtime architecture.
Do I need Tailwind CSS to use these components?
No. All components use pure Vanilla CSS with scoped design tokens defined in global.css. You do not need Tailwind or any heavy utility framework.
Can I use these components in commercial client projects?
Absolutely! The component kit is licensed under the permissive MIT license, allowing unlimited commercial and personal project usage with zero royalties.
How does this achieve 100/100 Lighthouse performance?
By shipping zero client-side JavaScript by default. Interactive controls use pure CSS or lightweight unobtrusive native DOM events only where strictly necessary.
How do I get help or report a bug?
You can open an issue on our GitHub repository or join our Discord developer community where maintainers and contributors are active daily.
How do I install the package in my project?
Simply run `npm install astro-component-kit` and import any component: `import { GlassCard } from 'astro-component-kit';`.
Still have questions?
Can't find the answer you're looking for? Chat to our friendly team.
Использование
Скопируйте и вставьте этот код на вашу страницу Astro:
---
import { FaqAccordionSection } from 'astro-component-kit';
---
<FaqAccordionSection /> ---
import { FaqAccordionSection } from 'astro-component-kit';
---
<FaqAccordionSection /> Ручная установка
Если вы не используете пакет npm, создайте файл и вставьте следующий код: src/components/lib/FAQAccordionSection.astro:
---
/**
* FaqAccordionSection — Full-page interactive FAQ section with category tabs, search filter, and accessible accordions.
*
* @param {string} badge - Eyebrow badge.
* @param {string} title - Section main heading.
* @param {string} subtitle - Supporting description text.
*/
interface Props {
badge?: string;
title?: string;
subtitle?: string;
className?: string;
}
const {
badge = "Frequently Asked Questions",
title = "Got Questions? We Have Answers",
subtitle = "Everything you need to know about the Astro Components Kit, licensing, updates, and custom integrations.",
className = ""
} = Astro.props;
const faqs = [
{
category: "general",
q: "Is this library compatible with Astro 5.x?",
a: "Yes! All components are built specifically for Astro 5.x and leverage Astro Content Collections, scoped styles, and zero-runtime architecture."
},
{
category: "general",
q: "Do I need Tailwind CSS to use these components?",
a: "No. All components use pure Vanilla CSS with scoped design tokens defined in global.css. You do not need Tailwind or any heavy utility framework."
},
{
category: "licensing",
q: "Can I use these components in commercial client projects?",
a: "Absolutely! The component kit is licensed under the permissive MIT license, allowing unlimited commercial and personal project usage with zero royalties."
},
{
category: "performance",
q: "How does this achieve 100/100 Lighthouse performance?",
a: "By shipping zero client-side JavaScript by default. Interactive controls use pure CSS or lightweight unobtrusive native DOM events only where strictly necessary."
},
{
category: "support",
q: "How do I get help or report a bug?",
a: "You can open an issue on our GitHub repository or join our Discord developer community where maintainers and contributors are active daily."
},
{
category: "licensing",
q: "How do I install the package in my project?",
a: "Simply run `npm install astro-component-kit` and import any component: `import { GlassCard } from 'astro-component-kit';`."
}
];
---
<section class={`faq-section ${className}`} aria-labelledby="faq-title">
<div class="faq-bg" aria-hidden="true">
<div class="faq-glow"></div>
</div>
<div class="container">
<!-- Header -->
<div class="section-header">
{badge && <span class="section-badge">{badge}</span>}
<h2 id="faq-title" class="section-title">{title}</h2>
<p class="section-subtitle">{subtitle}</p>
<!-- Category Filter Pills -->
<div class="faq-tabs" role="tablist">
<button class="faq-tab faq-tab--active" data-cat="all">All Questions</button>
<button class="faq-tab" data-cat="general">General</button>
<button class="faq-tab" data-cat="licensing">Licensing</button>
<button class="faq-tab" data-cat="performance">Performance</button>
<button class="faq-tab" data-cat="support">Support</button>
</div>
</div>
<!-- FAQ Accordions List -->
<div class="faq-list">
{faqs.map((faq, i) => (
<details class="faq-item" data-category={faq.category}>
<summary class="faq-question">
<span class="faq-question-text">{faq.q}</span>
<span class="faq-chevron" aria-hidden="true">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
</span>
</summary>
<div class="faq-answer">
<p>{faq.a}</p>
</div>
</details>
))}
</div>
<!-- Support Box -->
<div class="faq-support-box">
<div class="support-icon">💬</div>
<div class="support-info">
<h4>Still have questions?</h4>
<p>Can't find the answer you're looking for? Chat to our friendly team.</p>
</div>
<a href="#contact" class="support-btn">Get in Touch</a>
</div>
</div>
</section>
<script>
// Interactive category filter for FAQs
const tabs = document.querySelectorAll('.faq-tab');
const items = document.querySelectorAll<HTMLElement>('.faq-item');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('faq-tab--active'));
tab.classList.add('faq-tab--active');
const targetCat = tab.getAttribute('data-cat');
items.forEach(item => {
const itemCat = item.getAttribute('data-category');
if (targetCat === 'all' || itemCat === targetCat) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
});
});
</script>
<style>
.faq-section {
position: relative;
padding: var(--sp-20, 5rem) var(--sp-6, 1.5rem);
background: var(--c-bg-primary, #030712);
overflow: hidden;
}
.faq-bg {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
}
.faq-glow {
position: absolute;
top: 30%;
left: 50%;
transform: translateX(-50%);
width: 600px;
height: 450px;
background: radial-gradient(circle, rgba(99, 102, 241, 0.1), transparent 70%);
filter: blur(120px);
}
.container {
position: relative;
z-index: 1;
max-width: 900px;
margin: 0 auto;
}
.section-header {
text-align: center;
margin-bottom: 3rem;
}
.section-badge {
display: inline-flex;
padding: 0.35rem 0.9rem;
border-radius: 9999px;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
background: color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent);
color: #eab308;
border: 1px solid rgba(234, 179, 8, 0.25);
margin-bottom: var(--sp-4, 1rem);
}
.section-title {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 900;
color: #fff;
line-height: 1.15;
letter-spacing: -0.02em;
margin: 0 0 var(--sp-4, 1rem);
}
.section-subtitle {
font-size: 1.1rem;
color: #94a3b8;
line-height: 1.6;
margin: 0 0 2rem;
}
/* Filter Tabs */
.faq-tabs {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.faq-tab {
padding: 0.5rem 1.1rem;
background: rgba(15, 23, 42, 0.6);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
border-radius: 9999px;
color: #94a3b8;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.25s ease;
}
.faq-tab:hover {
color: #fff;
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.2);
}
.faq-tab--active {
background: rgba(234, 179, 8, 0.15);
color: #facc15;
border-color: rgba(234, 179, 8, 0.35);
}
/* FAQ Accordion Items */
.faq-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 3.5rem;
}
.faq-item {
background: rgba(15, 23, 42, 0.5);
backdrop-filter: blur(16px);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
border-radius: 16px;
overflow: hidden;
transition: border-color 0.3s ease, background 0.3s ease;
}
.faq-item:hover {
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.18);
}
.faq-item[open] {
background: rgba(20, 25, 50, 0.7);
border-color: rgba(99, 102, 241, 0.3);
}
.faq-question {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.35rem 1.75rem;
font-size: 1.1rem;
font-weight: 700;
color: #fff;
cursor: pointer;
user-select: none;
list-style: none;
}
.faq-question::-webkit-details-marker {
display: none;
}
.faq-chevron {
color: #94a3b8;
display: flex;
align-items: center;
transition: transform 0.3s ease, color 0.3s ease;
}
.faq-item[open] .faq-chevron {
transform: rotate(180deg);
color: #eab308;
}
.faq-answer {
padding: 0 1.75rem 1.5rem;
color: #cbd5e1;
font-size: 0.95rem;
line-height: 1.7;
}
.faq-answer p {
margin: 0;
}
/* Support Box */
.faq-support-box {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1.5rem;
padding: 1.75rem 2rem;
background: rgba(15, 23, 42, 0.6);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
border-radius: 20px;
flex-wrap: wrap;
}
.support-icon {
font-size: 2rem;
}
.support-info {
flex: 1;
min-width: 240px;
}
.support-info h4 {
font-size: 1.15rem;
font-weight: 800;
color: #fff;
margin: 0 0 0.25rem;
}
.support-info p {
font-size: 0.88rem;
color: #94a3b8;
margin: 0;
}
.support-btn {
padding: 0.75rem 1.4rem;
background: rgb(var(--ink-rgb, 255 255 255) / 0.08);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.15);
border-radius: 10px;
color: #fff;
font-size: 0.9rem;
font-weight: 700;
text-decoration: none;
transition: all 0.25s ease;
}
.support-btn:hover {
background: #eab308;
color: #000;
border-color: #eab308;
}
</style> ---
/**
* FaqAccordionSection — Full-page interactive FAQ section with category tabs, search filter, and accessible accordions.
*
* @param {string} badge - Eyebrow badge.
* @param {string} title - Section main heading.
* @param {string} subtitle - Supporting description text.
*/
interface Props {
badge?: string;
title?: string;
subtitle?: string;
className?: string;
}
const {
badge = "Frequently Asked Questions",
title = "Got Questions? We Have Answers",
subtitle = "Everything you need to know about the Astro Components Kit, licensing, updates, and custom integrations.",
className = ""
} = Astro.props;
const faqs = [
{
category: "general",
q: "Is this library compatible with Astro 5.x?",
a: "Yes! All components are built specifically for Astro 5.x and leverage Astro Content Collections, scoped styles, and zero-runtime architecture."
},
{
category: "general",
q: "Do I need Tailwind CSS to use these components?",
a: "No. All components use pure Vanilla CSS with scoped design tokens defined in global.css. You do not need Tailwind or any heavy utility framework."
},
{
category: "licensing",
q: "Can I use these components in commercial client projects?",
a: "Absolutely! The component kit is licensed under the permissive MIT license, allowing unlimited commercial and personal project usage with zero royalties."
},
{
category: "performance",
q: "How does this achieve 100/100 Lighthouse performance?",
a: "By shipping zero client-side JavaScript by default. Interactive controls use pure CSS or lightweight unobtrusive native DOM events only where strictly necessary."
},
{
category: "support",
q: "How do I get help or report a bug?",
a: "You can open an issue on our GitHub repository or join our Discord developer community where maintainers and contributors are active daily."
},
{
category: "licensing",
q: "How do I install the package in my project?",
a: "Simply run `npm install astro-component-kit` and import any component: `import { GlassCard } from 'astro-component-kit';`."
}
];
---
<section class={`faq-section ${className}`} aria-labelledby="faq-title">
<div class="faq-bg" aria-hidden="true">
<div class="faq-glow"></div>
</div>
<div class="container">
<!-- Header -->
<div class="section-header">
{badge && <span class="section-badge">{badge}</span>}
<h2 id="faq-title" class="section-title">{title}</h2>
<p class="section-subtitle">{subtitle}</p>
<!-- Category Filter Pills -->
<div class="faq-tabs" role="tablist">
<button class="faq-tab faq-tab--active" data-cat="all">All Questions</button>
<button class="faq-tab" data-cat="general">General</button>
<button class="faq-tab" data-cat="licensing">Licensing</button>
<button class="faq-tab" data-cat="performance">Performance</button>
<button class="faq-tab" data-cat="support">Support</button>
</div>
</div>
<!-- FAQ Accordions List -->
<div class="faq-list">
{faqs.map((faq, i) => (
<details class="faq-item" data-category={faq.category}>
<summary class="faq-question">
<span class="faq-question-text">{faq.q}</span>
<span class="faq-chevron" aria-hidden="true">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
</span>
</summary>
<div class="faq-answer">
<p>{faq.a}</p>
</div>
</details>
))}
</div>
<!-- Support Box -->
<div class="faq-support-box">
<div class="support-icon">💬</div>
<div class="support-info">
<h4>Still have questions?</h4>
<p>Can't find the answer you're looking for? Chat to our friendly team.</p>
</div>
<a href="#contact" class="support-btn">Get in Touch</a>
</div>
</div>
</section>
<script>
// Interactive category filter for FAQs
const tabs = document.querySelectorAll('.faq-tab');
const items = document.querySelectorAll<HTMLElement>('.faq-item');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('faq-tab--active'));
tab.classList.add('faq-tab--active');
const targetCat = tab.getAttribute('data-cat');
items.forEach(item => {
const itemCat = item.getAttribute('data-category');
if (targetCat === 'all' || itemCat === targetCat) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
});
});
</script>
<style>
.faq-section {
position: relative;
padding: var(--sp-20, 5rem) var(--sp-6, 1.5rem);
background: var(--c-bg-primary, #030712);
overflow: hidden;
}
.faq-bg {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
}
.faq-glow {
position: absolute;
top: 30%;
left: 50%;
transform: translateX(-50%);
width: 600px;
height: 450px;
background: radial-gradient(circle, rgba(99, 102, 241, 0.1), transparent 70%);
filter: blur(120px);
}
.container {
position: relative;
z-index: 1;
max-width: 900px;
margin: 0 auto;
}
.section-header {
text-align: center;
margin-bottom: 3rem;
}
.section-badge {
display: inline-flex;
padding: 0.35rem 0.9rem;
border-radius: 9999px;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
background: color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent);
color: #eab308;
border: 1px solid rgba(234, 179, 8, 0.25);
margin-bottom: var(--sp-4, 1rem);
}
.section-title {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 900;
color: #fff;
line-height: 1.15;
letter-spacing: -0.02em;
margin: 0 0 var(--sp-4, 1rem);
}
.section-subtitle {
font-size: 1.1rem;
color: #94a3b8;
line-height: 1.6;
margin: 0 0 2rem;
}
/* Filter Tabs */
.faq-tabs {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.faq-tab {
padding: 0.5rem 1.1rem;
background: rgba(15, 23, 42, 0.6);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
border-radius: 9999px;
color: #94a3b8;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.25s ease;
}
.faq-tab:hover {
color: #fff;
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.2);
}
.faq-tab--active {
background: rgba(234, 179, 8, 0.15);
color: #facc15;
border-color: rgba(234, 179, 8, 0.35);
}
/* FAQ Accordion Items */
.faq-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 3.5rem;
}
.faq-item {
background: rgba(15, 23, 42, 0.5);
backdrop-filter: blur(16px);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
border-radius: 16px;
overflow: hidden;
transition: border-color 0.3s ease, background 0.3s ease;
}
.faq-item:hover {
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.18);
}
.faq-item[open] {
background: rgba(20, 25, 50, 0.7);
border-color: rgba(99, 102, 241, 0.3);
}
.faq-question {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.35rem 1.75rem;
font-size: 1.1rem;
font-weight: 700;
color: #fff;
cursor: pointer;
user-select: none;
list-style: none;
}
.faq-question::-webkit-details-marker {
display: none;
}
.faq-chevron {
color: #94a3b8;
display: flex;
align-items: center;
transition: transform 0.3s ease, color 0.3s ease;
}
.faq-item[open] .faq-chevron {
transform: rotate(180deg);
color: #eab308;
}
.faq-answer {
padding: 0 1.75rem 1.5rem;
color: #cbd5e1;
font-size: 0.95rem;
line-height: 1.7;
}
.faq-answer p {
margin: 0;
}
/* Support Box */
.faq-support-box {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1.5rem;
padding: 1.75rem 2rem;
background: rgba(15, 23, 42, 0.6);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
border-radius: 20px;
flex-wrap: wrap;
}
.support-icon {
font-size: 2rem;
}
.support-info {
flex: 1;
min-width: 240px;
}
.support-info h4 {
font-size: 1.15rem;
font-weight: 800;
color: #fff;
margin: 0 0 0.25rem;
}
.support-info p {
font-size: 0.88rem;
color: #94a3b8;
margin: 0;
}
.support-btn {
padding: 0.75rem 1.4rem;
background: rgb(var(--ink-rgb, 255 255 255) / 0.08);
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.15);
border-radius: 10px;
color: #fff;
font-size: 0.9rem;
font-weight: 700;
text-decoration: none;
transition: all 0.25s ease;
}
.support-btn:hover {
background: #eab308;
color: #000;
border-color: #eab308;
}
</style>
Краткая информация
- Категория
- Секции страниц
- Имя файла
FAQAccordionSection.astro- Зависимости
- Нет — чистый Astro + CSS
- Теги
- faqaccordionquestionssupportaccessible