# SSS akordeonu: ücretsiz Shopify bölümü

> Yerel details öğeleriyle SSS akordeonu: en fazla 30 soru, isteğe bağlı gruplar, arama filtresi, tek açık mod ve isteğe bağlı FAQPage yapılandırılmış verisi.

SSS akordeonu, yerel HTML ile açılıp kapanan en fazla 30 soru ve cevabı listeleyen ücretsiz bir Shopify bölümüdür; bu yüzden JavaScript olmadan çalışır. İsteğe bağlı ekler bir arama filtresi, aynı anda tek açık cevap, grup başlıkları ve FAQPage JSON-LD ekler; Online Store 2.0 temalarında uygulama olmadan çalışır.

- **Kategori:** Navigasyon ve yardımcı bölümler
- **Kullanıldığı yerler:** Ana sayfa, Ürün, SSS sayfası, Her sayfa
- **Okuduğu veri:** Yalnızca içerik
- **Boyut:** 2 dosyada 33 KB, küçük bir betikle
- **Lisans:** MIT, © 2026 Lintel
- **Sayfa:** https://lintelagency.com/tr/kaynaklar/shopify-bolumleri/sss-akordeon
- **Canlı demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-faq.html
- **Eklenme tarihi:** 2026-10-02

## Ne işe yarar

- Siparişler, iadeler ve ürün bakımına göre gruplanmış ayrı bir SSS ya da yardım sayfası
- Satın alma alanının altında beden, malzeme ya da bakımla ilgili ürün sayfası soruları
- Ana sayfanın ya da sepet sayfasının alt kısmına yakın kargo ve iade cevapları

## Tema düzenleyici ayarları

Bölüm tema düzenleyicide “Lib · FAQ” adıyla görünür. Kimlikler, türler, etiketler ve varsayılan değerler bölümün şemasından gelir. Etiketler tema düzenleyicide göründüğü gibi İngilizcedir.

### Content

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `heading` | `inline_richtext` | Heading | Frequently asked questions |  |
| `heading_tag` | `select` | Heading tag | h2 | `h1`, `h2`, `h3`, `p` |
| `heading_size` | `select` | Heading size | medium | `small`, `medium`, `large`, `xlarge` |
| `text` | `richtext` | Intro text | `<p>Shipping, returns and caring for your pieces, answered.</p>` |  |

### Questions

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `group_questions` | `checkbox` | Group questions by their group label | `false` |  |
| `first_open` | `checkbox` | Open the first question | `false` |  |
| `one_open` | `checkbox` | Only one answer open at a time | `false` |  |
| `icon_style` | `select` | Icon | plus | `plus`, `chevron`, `none` |
| `item_style` | `select` | Question style | dividers | `dividers`, `cards` |
| `radius` | `range` | Corner radius (cards, search, contact box) | `12` | 0–24 px, step 2 |

### Search

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `show_search` | `checkbox` | Show search box | `false` |  |
| `search_label` | `text` | Search label | Search questions |  |
| `search_placeholder` | `text` | Search placeholder | Try 'returns' or 'glaze' |  |
| `no_results` | `text` | No results message | No questions match your search. Try another word or contact us. |  |

### Contact box

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `cta_text` | `richtext` | Text | `<p><strong>Still have questions?</strong> Our team answers within one working day.</p>` |  |
| `button_label` | `text` | Button label | Contact us |  |
| `button_url` | `url` | Button link | – |  |
| `button_style` | `select` | Button style | primary | `primary`, `outline`, `text` |
| `button_new_tab` | `checkbox` | Open link in a new tab | `false` |  |

### Layout

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `layout` | `select` | Layout | single | `single`, `two`, `split` |
| `section_width` | `select` | Width | page | `page`, `full` |
| `content_width` | `range` | Content max width | `800` | 560–1200 px, step 20 |
| `text_alignment` | `text_alignment` | Heading alignment on desktop | left |  |
| `text_alignment_mobile` | `select` | Heading alignment on mobile | left | `left`, `center`, `right` |

### Colors

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Background | #FAFAF9 |  |
| `color_bg_gradient` | `color_background` | Background gradient | – |  |
| `color_text` | `color` | Text | #1C1917 |  |
| `color_accent` | `color` | Accent (icons, button, focus ring) | #1C1917 |  |
| `color_accent_text` | `color` | Text on accent | #FAFAF9 |  |
| `color_card` | `color` | Card and search box background | #FFFFFF |  |
| `color_line` | `color` | Dividers and borders | #E7E5E4 |  |

### Spacing and visibility

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `padding_top` | `range` | Top padding on desktop | `80` | 0–200 px, step 4 |
| `padding_bottom` | `range` | Bottom padding on desktop | `80` | 0–200 px, step 4 |
| `padding_top_mobile` | `range` | Top padding on mobile | `48` | 0–160 px, step 4 |
| `padding_bottom_mobile` | `range` | Bottom padding on mobile | `48` | 0–160 px, step 4 |
| `show_on` | `select` | Show on | all | `all`, `desktop`, `mobile` |
| `anchor_id` | `text` | Anchor ID | – |  |

### Motion

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `animate` | `checkbox` | Animate answers opening | `true` |  |

### Search engines

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `structured_data` | `checkbox` | Output FAQPage structured data | `false` |  |

## Bloklar

Toplamda en fazla 30 blok.

### Question (`question`)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `question` | `text` | Question | How long does delivery take? |  |
| `answer` | `richtext` | Answer | `<p>Orders ship within two working days. Delivery usually takes three to five working days after that.</p>` |  |
| `group` | `text` | Group label | – |  |

## Kurulum

### Shopify yönetim panelinde

1. Canlı temanızda değil, bir kopyasında çalışın: Shopify yönetim panelinde **Online Mağaza > Temalar** sayfasına gidin, mevcut temanızın **…** menüsünü açın ve **Kopya oluştur**’u seçin.
2. Kopyada **…** menüsünü açın ve **Kodu düzenle**’yi seçin.
3. `sections` klasörüne `lib-faq.liquid` adında yeni bir dosya ekleyin, aşağıdaki kaynak koddan `sections/lib-faq.liquid` içeriğini yapıştırıp kaydedin.
4. `lib-button.liquid` dosyalarını da aynı şekilde `snippets` klasörüne ekleyin. Başka bir Lib bölümünden gelen aynı adlı bir snippet zaten varsa aynı dosyadır; tek kopya yeterli.
5. Kopyada **Özelleştir**’i açın, **Bölüm ekle**’yi seçin ve **Lib · FAQ** bölümünü ekleyin. Örnek içeriği kendi içeriğinizle değiştirin, renkleri ayarlayın.
6. Kopyayı önizleyin, her şey doğru göründüğünde yayınlayın.

### Shopify CLI ile

Yerel tema klasörünüzde dosyaları indirin ve yalnızca bunları yayında olmayan bir temaya gönderin (temanın kimliğini `shopify theme list` gösterir):

```sh
curl -fsSL -o sections/lib-faq.liquid https://lintelagency.com/resources/shopify-sections/files/lib-faq.liquid
curl -fsSL -o snippets/lib-button.liquid https://lintelagency.com/resources/shopify-sections/files/lib-button.liquid
shopify theme push --theme <unpublished-theme-id> --only sections/lib-faq.liquid --only snippets/lib-button.liquid
```

Canlı temaya asla göndermeyin: her zaman yayında olmayan bir temanın kimliğini verin, `--live` ya da `--allow-live` kullanmayın. Ardından bölümü yukarıdaki gibi tema düzenleyicide ekleyin.

## Dosyalar

- [sections/lib-faq.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-faq.liquid): `sections/` klasörüne
- [snippets/lib-button.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-button.liquid): `snippets/` klasörüne

## Sık sorulan sorular

### Akordeon JavaScript olmadan çalışır mı?

Evet. Her soru yerel bir details ve summary öğesidir; yalnızca tarayıcıyla açılıp kapanır ve klavyeyle çalışır. JavaScript yalnızca, onsuz gizli kalan arama kutusu için ve tek cevap açık modunu yerel olarak desteklemeyen tarayıcılarda bu mod için kullanılır.

### Kaç soru ekleyebilirim, gruplayabilir miyim?

En fazla 30 soru bloğu. Sorulara bir grup etiketi verin ve gruplamayı açın: aynı etiketli sorular, etiketlerin ilk göründüğü sırayla, o etiketin başlığı altında birlikte listelenir. Etiketsiz sorular önce listelenir.

### SSS yapılandırılmış verisi ekler mi?

Yalnızca varsayılan olarak kapalı olan "Output FAQPage structured data" seçeneğini işaretlerseniz. Bölüm bu durumda sorulardan, cevaplardaki HTML temizlenerek oluşturulmuş schema.org FAQPage JSON-LD üretir. Sayfa başına tek bir SSS’de kullanın; temanız ya da bir uygulama zaten SSS işaretlemesi üretiyorsa kullanmayın. Yapılandırılmış veri aramada zengin sonucu garanti etmez.

### Arama kutusu nasıl çalışır?

Ziyaretçi yazarken, sorusu ya da cevabı bu kelimeleri içermeyen sorular gizlenir, boş kalan gruplar da gizlenir ve hiçbir şey eşleşmezse belirlediğiniz mesaj gösterilir. Escape aramayı temizler. Zaten sayfada olan soruları filtreler ve hiç ağ isteği yapmaz.

### Cevap açılırken animasyon olur mu?

details içeriğini canlandırabilen tarayıcılarda hareket ayarı açıkken cevaplar kayarak açılır. Diğerlerinde anında açılır; ziyaretçi azaltılmış hareket tercih ettiğinde animasyon her zaman kapalıdır.

## Kaynak kod

### sections/lib-faq.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  FAQ accordion on native <details>/<summary>: every answer opens and closes without JavaScript.
  A small custom element adds the optional extras: one answer open at a time and a search filter.
  Questions can be grouped under headings by the block's group label.
  Optional FAQPage JSON-LD built from the blocks (checkbox, off by default).
  Depends on: snippets/lib-button.liquid
{%- endcomment -%}

{%- liquid
  assign s = section.settings
  assign heading_tag = s.heading_tag | default: 'h2'
  case heading_tag
    when 'h1'
      assign group_tag = 'h2'
    when 'h2'
      assign group_tag = 'h3'
    else
      assign group_tag = 'h4'
  endcase

  comment
    Group labels in order of first appearance, wrapped in a delimiter so "Ship" never matches "Shipping".
    Questions without a label are listed first, without a heading.
  endcomment
  assign sep = '|~|'
  assign group_list = sep
  assign has_ungrouped = false
  for block in section.blocks
    assign g = block.settings.group | strip
    if g == blank
      assign has_ungrouped = true
    else
      assign needle = sep | append: g | append: sep
      unless group_list contains needle
        assign group_list = group_list | append: g | append: sep
      endunless
    endif
  endfor
  assign use_groups = false
  if s.group_questions and group_list != sep
    assign use_groups = true
  endif

  assign has_header = false
  if s.heading != blank or s.text != blank
    assign has_header = true
  endif
  assign has_cta = false
  if s.cta_text != blank or s.button_label != blank
    assign has_cta = true
  endif
  assign list_name = 'lib-faq-' | append: section.id
-%}

{%- capture cta -%}
  {%- if has_cta -%}
    <div class="lib-faq__cta lib-faq__cta--CTA_POS">
      {%- if s.cta_text != blank -%}
        <div class="lib-faq__cta-text">{{ s.cta_text }}</div>
      {%- endif -%}
      {%- render 'lib-button',
        label: s.button_label,
        url: s.button_url,
        style: s.button_style,
        new_tab: s.button_new_tab
      -%}
    </div>
  {%- endif -%}
{%- endcapture -%}

<div
  class="lib-faq lib-faq--{{ s.section_width }}"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-layout="{{ s.layout }}"
  data-style="{{ s.item_style }}"
  data-icon="{{ s.icon_style }}"
  {% if s.animate %}
    data-animate
  {% endif %}
  style="
    --lib-bg: {{ s.color_bg }};
    {% if s.color_bg_gradient != blank %}--lib-bg-image: {{ s.color_bg_gradient }};{% endif %}
    --lib-text: {{ s.color_text }};
    --lib-accent: {{ s.color_accent }};
    --lib-accent-text: {{ s.color_accent_text }};
    --lib-card: {{ s.color_card }};
    --lib-line: {{ s.color_line }};
    --lib-radius: {{ s.radius }}px;
    --lib-max: {{ s.content_width }}px;
    --lib-pt: {{ s.padding_top }}px;
    --lib-pb: {{ s.padding_bottom }}px;
    --lib-pt-m: {{ s.padding_top_mobile }}px;
    --lib-pb-m: {{ s.padding_bottom_mobile }}px;
  "
>
  <div class="lib-faq__inner">
    {%- if has_header or s.layout == 'split' -%}
      <header class="lib-faq__header" data-align="{{ s.text_alignment }}" data-align-m="{{ s.text_alignment_mobile }}">
        {%- if s.heading != blank -%}
          <{{ heading_tag }} class="lib-faq__heading lib-faq__heading--{{ s.heading_size }}">
            {{- s.heading -}}
          </{{ heading_tag }}>
        {%- endif -%}
        {%- if s.text != blank -%}
          <div class="lib-faq__intro">{{ s.text }}</div>
        {%- endif -%}
        {%- if s.layout == 'split' -%}
          {{ cta | replace: 'CTA_POS', 'side' }}
        {%- endif -%}
      </header>
    {%- endif -%}

    <lib-faq-accordion
      class="lib-faq__body"
      {% if s.one_open %}
        data-exclusive
      {% endif %}
    >
      {%- if s.show_search and section.blocks.size > 0 -%}
        <div class="lib-faq__search" data-search hidden>
          <label class="lib-faq__search-label" for="LibFaqSearch-{{ section.id }}">
            {{- s.search_label | default: 'Search questions' | escape -}}
          </label>
          <div class="lib-faq__search-field">
            <svg class="lib-faq__search-icon" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true" focusable="false">
              <circle cx="8.5" cy="8.5" r="5.75" fill="none" stroke="currentColor" stroke-width="1.6"/>
              <path d="m13 13 4.5 4.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
            </svg>
            <input
              class="lib-faq__search-input"
              id="LibFaqSearch-{{ section.id }}"
              type="search"
              autocomplete="off"
              placeholder="{{ s.search_placeholder | escape }}"
              aria-controls="LibFaqList-{{ section.id }}"
            >
          </div>
          <p class="lib-faq__empty" role="status" data-empty-text="{{ s.no_results | escape }}"></p>
        </div>
      {%- endif -%}

      <div class="lib-faq__groups" id="LibFaqList-{{ section.id }}">
        {%- if section.blocks.size == 0 -%}
          <p class="lib-faq__placeholder">Add question blocks to fill this FAQ.</p>
        {%- endif -%}

        {%- liquid
          comment
            Pass 0 lists questions without a group label (or all questions when grouping is off);
            each following pass lists one group under its heading.
          endcomment
          if use_groups
            assign pass_str = group_list
            if has_ungrouped
              assign pass_str = '__none__' | append: group_list
            endif
          else
            assign pass_str = '__all__'
          endif
          assign passes = pass_str | split: sep
          assign first_done = false
        -%}

        {%- for pass in passes -%}
          {%- if pass == blank -%}{%- continue -%}{%- endif -%}
          <div class="lib-faq__group" data-group>
            {%- if pass != '__none__' and pass != '__all__' -%}
              <{{ group_tag }} class="lib-faq__group-heading">{{ pass | escape }}</{{ group_tag }}>
            {%- endif -%}
            <div class="lib-faq__list">
              {%- for block in section.blocks -%}
                {%- liquid
                  assign b = block.settings
                  assign g = b.group | strip
                  assign show = false
                  if pass == '__all__'
                    assign show = true
                  elsif pass == '__none__' and g == blank
                    assign show = true
                  elsif g == pass
                    assign show = true
                  endif
                -%}
                {%- if show and b.question != blank -%}
                  <details
                    class="lib-faq__item"
                    {% if s.one_open %}
                      name="{{ list_name }}"
                    {% endif %}
                    {% if s.first_open and first_done == false %}
                      open
                    {% endif %}
                    {{ block.shopify_attributes }}
                  >
                    <summary class="lib-faq__question">
                      <span class="lib-faq__question-text">{{ b.question | escape }}</span>
                      {%- if s.icon_style != 'none' -%}
                        <span class="lib-faq__icon" aria-hidden="true">
                          {%- if s.icon_style == 'chevron' -%}
                            <svg viewBox="0 0 16 16" width="16" height="16" focusable="false">
                              <path d="m3.5 6 4.5 4.5L12.5 6" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
                            </svg>
                          {%- else -%}
                            <svg viewBox="0 0 16 16" width="16" height="16" focusable="false">
                              <path d="M2.5 8h11" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
                              <path class="lib-faq__icon-v" d="M8 2.5v11" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
                            </svg>
                          {%- endif -%}
                        </span>
                      {%- endif -%}
                    </summary>
                    <div class="lib-faq__answer">{{ b.answer }}</div>
                  </details>
                  {%- assign first_done = true -%}
                {%- endif -%}
              {%- endfor -%}
            </div>
          </div>
        {%- endfor -%}
      </div>
    </lib-faq-accordion>

    {{ cta | replace: 'CTA_POS', 'bottom' }}
  </div>
</div>

{%- if s.structured_data and section.blocks.size > 0 -%}
  {%- assign ld_first = true -%}
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [
        {%- for block in section.blocks -%}
          {%- liquid
            assign q = block.settings.question | strip_html | strip
            assign a = block.settings.answer | strip_html | strip
          -%}
          {%- if q != blank and a != blank -%}
            {%- unless ld_first %},{% endunless -%}
            {
              "@type": "Question",
              "name": {{ q | json }},
              "acceptedAnswer": { "@type": "Answer", "text": {{ a | json }} }
            }
            {%- assign ld_first = false -%}
          {%- endif -%}
        {%- endfor -%}
      ]
    }
  </script>
{%- endif -%}

{% stylesheet %}
  .lib-faq {
    background-color: var(--lib-bg);
    background-image: var(--lib-bg-image, none);
    color: var(--lib-text);
    padding: var(--lib-pt) 1rem var(--lib-pb);
  }
  .lib-faq__inner {
    max-width: 1200px;
    margin: 0 auto;
    display: grid;
    gap: clamp(1.75rem, 4vw, 2.75rem);
  }
  .lib-faq--full .lib-faq__inner { max-width: none; }
  .lib-faq[data-layout='single'] .lib-faq__inner { max-width: var(--lib-max); }
  .lib-faq[hidden], .lib-faq [hidden] { display: none !important; }
  @media (max-width: 749px) {
    .lib-faq { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); }
    .lib-faq[data-show='desktop'] { display: none; }
  }
  @media (min-width: 750px) {
    .lib-faq[data-show='mobile'] { display: none; }
  }
  @media (min-width: 990px) {
    .lib-faq[data-layout='split'] .lib-faq__inner {
      grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
      align-items: start;
      gap: clamp(2.5rem, 6vw, 5rem);
    }
    .lib-faq[data-layout='split'] .lib-faq__header { position: sticky; top: 2rem; }
    .lib-faq[data-layout='two'] .lib-faq__list {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      column-gap: 2.5rem;
      align-items: start;
    }
    .lib-faq[data-layout='two'][data-style='cards'] .lib-faq__list { column-gap: 0.75rem; }
  }

  /* Header and alignment: desktop, then mobile override. */
  .lib-faq__header { display: flex; flex-direction: column; align-items: flex-start; text-align: left; }
  .lib-faq__header[data-align='center'] { align-items: center; text-align: center; }
  .lib-faq__header[data-align='right'] { align-items: flex-end; text-align: right; }
  @media (max-width: 749px) {
    .lib-faq__header[data-align-m='left'] { align-items: flex-start; text-align: left; }
    .lib-faq__header[data-align-m='center'] { align-items: center; text-align: center; }
    .lib-faq__header[data-align-m='right'] { align-items: flex-end; text-align: right; }
  }
  .lib-faq__heading {
    margin: 0;
    font-size: clamp(1.75rem, 3.5vw, 2.75rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
    text-wrap: balance;
  }
  .lib-faq__heading--small { font-size: clamp(1.5rem, 2.5vw, 2rem); }
  .lib-faq__heading--large { font-size: clamp(2rem, 4.5vw, 3.5rem); }
  .lib-faq__heading--xlarge { font-size: clamp(2.5rem, 6vw, 4.5rem); }
  .lib-faq__intro {
    margin-top: 1rem;
    max-width: 38rem;
    font-size: 1.0625rem;
    line-height: 1.6;
    opacity: 0.75;
  }
  .lib-faq__intro > :first-child, .lib-faq__cta-text > :first-child, .lib-faq__answer > :first-child { margin-top: 0; }
  .lib-faq__intro > :last-child, .lib-faq__cta-text > :last-child, .lib-faq__answer > :last-child { margin-bottom: 0; }

  /* Search */
  .lib-faq__search { margin-bottom: 1.5rem; }
  .lib-faq__search-label { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; font-weight: 600; }
  .lib-faq__search-field { position: relative; }
  .lib-faq__search-icon { position: absolute; inset-inline-start: 1rem; top: 50%; translate: 0 -50%; opacity: 0.55; pointer-events: none; }
  .lib-faq__search-input {
    width: 100%;
    min-height: 3rem;
    padding: 0.75rem 1rem 0.75rem 2.75rem;
    border: 1px solid var(--lib-line);
    border-radius: var(--lib-radius);
    background: var(--lib-card);
    color: inherit;
    font: inherit;
    font-size: 1rem;
  }
  .lib-faq__search-input::placeholder { color: inherit; opacity: 0.5; }
  .lib-faq__search-input:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; }
  .lib-faq__empty { margin: 1rem 0 0; opacity: 0.75; }
  .lib-faq__empty:empty { display: none; }

  /* Groups and items */
  .lib-faq__groups { display: grid; gap: 2.5rem; }
  .lib-faq__group-heading {
    margin: 0 0 0.75rem;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.6;
  }
  .lib-faq__list { display: grid; }
  .lib-faq[data-style='dividers'] .lib-faq__list { border-top: 1px solid var(--lib-line); }
  .lib-faq[data-style='dividers'] .lib-faq__item { border-bottom: 1px solid var(--lib-line); }
  .lib-faq[data-style='cards'] .lib-faq__list { gap: 0.75rem; }
  .lib-faq[data-style='cards'] .lib-faq__item {
    background: var(--lib-card);
    border: 1px solid var(--lib-line);
    border-radius: var(--lib-radius);
  }
  @media (min-width: 990px) {
    /* Two columns with dividers: each column keeps its own top rule. */
    .lib-faq[data-layout='two'][data-style='dividers'] .lib-faq__list { border-top: 0; }
    .lib-faq[data-layout='two'][data-style='dividers'] .lib-faq__item:nth-child(-n + 2) { border-top: 1px solid var(--lib-line); }
  }
  .lib-faq__question {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 0;
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.4;
    cursor: pointer;
    list-style: none;
  }
  .lib-faq__question::-webkit-details-marker { display: none; }
  .lib-faq__question::marker { content: ''; }
  .lib-faq[data-style='cards'] .lib-faq__question { padding-inline: 1.25rem; }
  .lib-faq__question:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; border-radius: 4px; }
  .lib-faq__question:hover .lib-faq__question-text { text-decoration: underline; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
  .lib-faq__icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    color: var(--lib-accent);
    background: color-mix(in srgb, var(--lib-accent) 10%, transparent);
  }
  .lib-faq__icon svg, .lib-faq__icon-v { transition: transform 0.25s ease; transform-origin: center; }
  .lib-faq__item[open] .lib-faq__icon-v { transform: rotate(90deg); opacity: 0; }
  .lib-faq[data-icon='chevron'] .lib-faq__item[open] .lib-faq__icon svg { transform: rotate(180deg); }
  .lib-faq__answer {
    padding: 0 0 1.25rem;
    max-width: 46rem;
    line-height: 1.65;
    opacity: 0.8;
  }
  .lib-faq[data-style='cards'] .lib-faq__answer { padding-inline: 1.25rem; }
  .lib-faq__answer a { color: inherit; text-underline-offset: 0.2em; }
  .lib-faq__answer a:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; }
  .lib-faq__placeholder { margin: 0; padding: 2rem; border: 1px dashed var(--lib-line); border-radius: var(--lib-radius); text-align: center; opacity: 0.7; }

  /* Call to action */
  .lib-faq__cta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    padding: 1.5rem;
    border-radius: var(--lib-radius);
    background: color-mix(in srgb, var(--lib-text) 5%, transparent);
  }
  .lib-faq__cta-text { line-height: 1.5; }
  /* Split layout: the box sits under the heading on desktop and after the questions on mobile. */
  .lib-faq__cta--side { display: none; }
  @media (min-width: 990px) {
    .lib-faq[data-layout='split'] .lib-faq__cta--side { display: flex; }
    .lib-faq[data-layout='split'] .lib-faq__cta--bottom { display: none; }
  }
  .lib-faq__header .lib-faq__cta {
    margin-top: 2rem;
    padding: 0;
    background: none;
    flex-direction: column;
    align-items: inherit;
  }

  /* Motion: smooth open where the browser supports animating <details> content. */
  @media (prefers-reduced-motion: no-preference) {
    .lib-faq[data-animate] { interpolate-size: allow-keywords; }
    .lib-faq[data-animate] .lib-faq__item::details-content {
      block-size: 0;
      overflow: hidden;
      transition: block-size 0.3s ease, content-visibility 0.3s allow-discrete;
    }
    .lib-faq[data-animate] .lib-faq__item[open]::details-content { block-size: auto; }
  }
  @media (prefers-reduced-motion: reduce) {
    .lib-faq__icon svg, .lib-faq__icon-v { transition: none; }
  }
{% endstylesheet %}

{% javascript %}
  if (!customElements.get('lib-faq-accordion')) {
    customElements.define(
      'lib-faq-accordion',
      class extends HTMLElement {
        connectedCallback() {
          this.items = () => [...this.querySelectorAll('details.lib-faq__item')];

          // One open at a time. Native <details name> already does this in current browsers;
          // this covers older ones.
          if (this.hasAttribute('data-exclusive')) {
            this.addEventListener(
              'toggle',
              (e) => {
                const opened = e.target;
                if (!(opened instanceof HTMLDetailsElement) || !opened.open) return;
                for (const item of this.items()) if (item !== opened && item.open) item.open = false;
              },
              true
            );
          }

          const search = this.querySelector('[data-search]');
          const input = search && search.querySelector('input');
          if (!input) return;
          const empty = search.querySelector('.lib-faq__empty');
          search.hidden = false;
          input.addEventListener('input', () => this.filter(input.value, empty));
          input.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && input.value) {
              input.value = '';
              this.filter('', empty);
            }
          });
        }

        filter(raw, empty) {
          const query = raw.trim().toLowerCase();
          let shown = 0;
          for (const item of this.items()) {
            const match = !query || item.textContent.toLowerCase().includes(query);
            item.hidden = !match;
            if (match) shown++;
          }
          for (const group of this.querySelectorAll('[data-group]')) {
            group.hidden = !group.querySelector('details.lib-faq__item:not([hidden])');
          }
          if (empty) empty.textContent = shown ? '' : empty.dataset.emptyText || '';
        }
      }
    );
  }
{% endjavascript %}

{% schema %}
{
  "name": "Lib · FAQ",
  "tag": "section",
  "class": "lib-section",
  "max_blocks": 30,
  "settings": [
    { "type": "header", "content": "Content" },
    { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Frequently asked questions" },
    {
      "type": "select",
      "id": "heading_tag",
      "label": "Heading tag",
      "info": "Use H1 only when this is the page's main heading. Group headings use the next level down.",
      "options": [
        { "value": "h1", "label": "H1" },
        { "value": "h2", "label": "H2" },
        { "value": "h3", "label": "H3" },
        { "value": "p", "label": "Paragraph" }
      ],
      "default": "h2"
    },
    {
      "type": "select",
      "id": "heading_size",
      "label": "Heading size",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "xlarge", "label": "Extra large" }
      ],
      "default": "medium"
    },
    { "type": "richtext", "id": "text", "label": "Intro text", "default": "<p>Shipping, returns and caring for your pieces, answered.</p>" },

    { "type": "header", "content": "Questions" },
    { "type": "checkbox", "id": "group_questions", "label": "Group questions by their group label", "info": "Questions with the same group label are listed together under that label as a heading, in the order the labels first appear.", "default": false },
    { "type": "checkbox", "id": "first_open", "label": "Open the first question", "default": false },
    { "type": "checkbox", "id": "one_open", "label": "Only one answer open at a time", "default": false },
    {
      "type": "select",
      "id": "icon_style",
      "label": "Icon",
      "options": [
        { "value": "plus", "label": "Plus" },
        { "value": "chevron", "label": "Chevron" },
        { "value": "none", "label": "None" }
      ],
      "default": "plus"
    },
    {
      "type": "select",
      "id": "item_style",
      "label": "Question style",
      "options": [
        { "value": "dividers", "label": "Divider lines" },
        { "value": "cards", "label": "Cards" }
      ],
      "default": "dividers"
    },
    { "type": "range", "id": "radius", "label": "Corner radius (cards, search, contact box)", "min": 0, "max": 24, "step": 2, "unit": "px", "default": 12 },

    { "type": "header", "content": "Search" },
    { "type": "checkbox", "id": "show_search", "label": "Show search box", "info": "Filters the questions as visitors type. Needs JavaScript; without it the box stays hidden.", "default": false },
    { "type": "text", "id": "search_label", "label": "Search label", "default": "Search questions", "visible_if": "{{ section.settings.show_search }}" },
    { "type": "text", "id": "search_placeholder", "label": "Search placeholder", "default": "Try 'returns' or 'glaze'", "visible_if": "{{ section.settings.show_search }}" },
    { "type": "text", "id": "no_results", "label": "No results message", "default": "No questions match your search. Try another word or contact us.", "visible_if": "{{ section.settings.show_search }}" },

    { "type": "header", "content": "Contact box" },
    { "type": "richtext", "id": "cta_text", "label": "Text", "default": "<p><strong>Still have questions?</strong> Our team answers within one working day.</p>" },
    { "type": "text", "id": "button_label", "label": "Button label", "default": "Contact us" },
    { "type": "url", "id": "button_url", "label": "Button link" },
    {
      "type": "select",
      "id": "button_style",
      "label": "Button style",
      "options": [
        { "value": "primary", "label": "Solid" },
        { "value": "outline", "label": "Outline" },
        { "value": "text", "label": "Text link" }
      ],
      "default": "primary"
    },
    { "type": "checkbox", "id": "button_new_tab", "label": "Open link in a new tab", "default": false },

    { "type": "header", "content": "Layout" },
    {
      "type": "select",
      "id": "layout",
      "label": "Layout",
      "options": [
        { "value": "single", "label": "Single column" },
        { "value": "two", "label": "Two columns on desktop" },
        { "value": "split", "label": "Heading left, questions right" }
      ],
      "default": "single"
    },
    {
      "type": "select",
      "id": "section_width",
      "label": "Width",
      "options": [
        { "value": "page", "label": "Page width" },
        { "value": "full", "label": "Full width" }
      ],
      "default": "page"
    },
    { "type": "range", "id": "content_width", "label": "Content max width", "info": "Single column layout only.", "min": 560, "max": 1200, "step": 20, "unit": "px", "default": 800, "visible_if": "{{ section.settings.layout == 'single' }}" },
    { "type": "text_alignment", "id": "text_alignment", "label": "Heading alignment on desktop", "default": "left" },
    {
      "type": "select",
      "id": "text_alignment_mobile",
      "label": "Heading alignment on mobile",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" },
        { "value": "right", "label": "Right" }
      ],
      "default": "left"
    },

    { "type": "header", "content": "Colors" },
    { "type": "color", "id": "color_bg", "label": "Background", "default": "#FAFAF9" },
    { "type": "color_background", "id": "color_bg_gradient", "label": "Background gradient", "info": "Optional. Covers the background color." },
    { "type": "color", "id": "color_text", "label": "Text", "default": "#1C1917" },
    { "type": "color", "id": "color_accent", "label": "Accent (icons, button, focus ring)", "default": "#1C1917" },
    { "type": "color", "id": "color_accent_text", "label": "Text on accent", "default": "#FAFAF9" },
    { "type": "color", "id": "color_card", "label": "Card and search box background", "default": "#FFFFFF" },
    { "type": "color", "id": "color_line", "label": "Dividers and borders", "default": "#E7E5E4" },

    { "type": "header", "content": "Spacing and visibility" },
    { "type": "range", "id": "padding_top", "label": "Top padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 },
    { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 },
    { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 },
    { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 },
    {
      "type": "select",
      "id": "show_on",
      "label": "Show on",
      "options": [
        { "value": "all", "label": "All devices" },
        { "value": "desktop", "label": "Desktop only" },
        { "value": "mobile", "label": "Mobile only" }
      ],
      "default": "all"
    },
    { "type": "text", "id": "anchor_id", "label": "Anchor ID", "info": "Optional. Link to this section with #your-id." },

    { "type": "header", "content": "Motion" },
    { "type": "checkbox", "id": "animate", "label": "Animate answers opening", "info": "In browsers that support it. Always off when the visitor prefers reduced motion.", "default": true },

    { "type": "header", "content": "Search engines" },
    { "type": "checkbox", "id": "structured_data", "label": "Output FAQPage structured data", "info": "Adds schema.org FAQPage JSON-LD built from the questions, with formatting removed from answers. Use it on one FAQ per page, and only when your theme or an app does not already output FAQ markup.", "default": false }
  ],
  "blocks": [
    {
      "type": "question",
      "name": "Question",
      "settings": [
        { "type": "text", "id": "question", "label": "Question", "default": "How long does delivery take?" },
        { "type": "richtext", "id": "answer", "label": "Answer", "default": "<p>Orders ship within two working days. Delivery usually takes three to five working days after that.</p>" },
        { "type": "text", "id": "group", "label": "Group label", "info": "Optional. Used as a heading when \"Group questions\" is on." }
      ]
    }
  ],
  "presets": [
    {
      "name": "Lib · FAQ",
      "blocks": [
        { "type": "question", "settings": { "group": "Orders and delivery", "question": "How long does delivery take?", "answer": "<p>Orders ship from our studio within two working days. Delivery usually takes three to five working days after that, and you get a tracking link by email as soon as your parcel leaves.</p>" } },
        { "type": "question", "settings": { "group": "Orders and delivery", "question": "Do you ship internationally?", "answer": "<p>Yes, to most of Europe, the UK, the US and Canada. Duties and shipping costs are shown at checkout before you pay.</p>" } },
        { "type": "question", "settings": { "group": "Orders and delivery", "question": "Can I change or cancel my order?", "answer": "<p>Write to us within 12 hours of ordering and we will change or cancel it. After that your order is usually already packed.</p>" } },
        { "type": "question", "settings": { "group": "Returns", "question": "What is your returns policy?", "answer": "<p>Unused pieces can be returned within 30 days for a full refund. Start a return from the link in your shipping email.</p>" } },
        { "type": "question", "settings": { "group": "Returns", "question": "What if something arrives broken?", "answer": "<p>Send us a photo within seven days of delivery and we will replace the piece or refund it. You do not need to send the broken piece back.</p>" } },
        { "type": "question", "settings": { "group": "Product care", "question": "Is the stoneware dishwasher safe?", "answer": "<p>Our glazed stoneware is dishwasher and microwave safe. Pieces with an unglazed base last longer when washed by hand.</p>" } },
        { "type": "question", "settings": { "group": "Product care", "question": "Why does my piece look slightly different from the photo?", "answer": "<p>Every piece is thrown and glazed by hand, so colour and speckling vary from one to the next. No two are exactly alike.</p>" } }
      ]
    }
  ]
}
{% endschema %}
```

### snippets/lib-button.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{% doc %}
  Animated call-to-action link. Light sweep on hover, arrow slides right.
  Colors come from the parent section's --lib-accent / --lib-accent-text / --lib-text vars.
  Inspired by Uiverse.io button patterns; rewritten for themes, no dependencies.

  @param {string} label - Button text
  @param {string} [url] - Link target; renders a disabled-looking span when blank
  @param {string} [style] - 'primary' (default), 'outline' or 'text'
  @param {boolean} [new_tab] - Open the link in a new tab
  @param {boolean} [arrow] - Show the trailing arrow (default true)

  @example
  {% render 'lib-button', label: section.settings.button_label, url: section.settings.button_url, style: 'outline' %}
{% enddoc %}

{%- liquid
  assign btn_style = style | default: 'primary'
  assign show_arrow = true
  if arrow == false
    assign show_arrow = false
  endif
-%}

{%- unless label == blank -%}
{%- capture inner -%}
  <span class="lib-btn__label">{{ label | escape }}</span>
  {%- if show_arrow -%}
    <svg class="lib-btn__arrow" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false">
      <path d="M3 8h9M8.5 4.5 12 8l-3.5 3.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  {%- endif -%}
{%- endcapture -%}

{%- if url != blank -%}
  <a
    class="lib-btn lib-btn--{{ btn_style }}"
    href="{{ url }}"
    {% if new_tab %}
      target="_blank" rel="noopener"
    {% endif %}
  >
    {{- inner -}}
  </a>
{%- else -%}
  <span class="lib-btn lib-btn--{{ btn_style }}" aria-disabled="true">{{ inner }}</span>
{%- endif -%}
{%- endunless -%}

{% stylesheet %}
  .lib-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.85em 1.5em;
    border-radius: var(--lib-radius, 999px);
    font: inherit;
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    overflow: hidden;
    isolation: isolate;
    transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
  }
  .lib-btn--primary {
    background: var(--lib-accent, #111);
    color: var(--lib-accent-text, #fff);
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.12);
  }
  .lib-btn--outline {
    background: transparent;
    color: var(--lib-text, #111);
    box-shadow: inset 0 0 0 1.5px currentColor;
  }
  .lib-btn--text {
    padding-inline: 0;
    background: none;
    color: var(--lib-text, #111);
    text-decoration: underline;
    text-underline-offset: 0.3em;
    overflow: visible;
  }
  .lib-btn--text::before { display: none; }
  .lib-btn--text:hover { transform: none; box-shadow: none; }
  .lib-btn::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(110deg, transparent 30%, rgb(255 255 255 / 0.35) 50%, transparent 70%);
    transform: translateX(-120%);
    transition: transform 0.6s ease;
  }
  .lib-btn--outline::before {
    background: linear-gradient(110deg, transparent 30%, rgb(127 127 127 / 0.18) 50%, transparent 70%);
  }
  .lib-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 20px -8px rgb(0 0 0 / 0.35);
  }
  .lib-btn:hover::before { transform: translateX(120%); }
  .lib-btn__arrow { transition: transform 0.2s ease; }
  .lib-btn:hover .lib-btn__arrow { transform: translateX(3px); }
  .lib-btn:focus-visible {
    outline: 2px solid var(--lib-accent, #111);
    outline-offset: 3px;
  }
  .lib-btn[aria-disabled='true'] { pointer-events: none; }
  @media (prefers-reduced-motion: reduce) {
    .lib-btn, .lib-btn::before, .lib-btn__arrow { transition: none; }
    .lib-btn:hover { transform: none; }
  }
{% endstylesheet %}
```

## Lisans

MIT Lisansı, © 2026 Lintel. Kendi mağazanızda ya da müşteri işlerinde ücretsiz kullanabilir, değiştirebilir ve yayınlayabilirsiniz; her dosyanın başındaki lisans satırını koruyun.
