# İletişim formu: ücretsiz Shopify bölümü

> Ad, e-posta, telefon, mesaj ve ek alanlarla Shopify’ın kendi iletişim formu; yanında görsel, adres, harita bağlantısı, e-posta ve çalışma saatleri sütunu.

İletişim formu, Shopify’ın kendi iletişim formunu kullanan ücretsiz bir Shopify bölümüdür; mesajlar uygulama gerekmeden mağazanın gönderici e-posta adresine ulaşır. Ad, e-posta, telefon ve mesaj alanları hazırdır; ek alanlar (kısa metin, uzun metin, seçim listesi, onay kutusu) bloklarla eklenir ve formun yanındaki isteğe bağlı sütun bir görsel, harita bağlantılı adres, e-posta, telefon ve çalışma saatlerini gösterir. Hatalar alanların üstünde listelenir, her alanın görünür bir etiketi vardır ve Online Store 2.0 temalarında çalışır.

- **Kategori:** Formlar ve bülten
- **Kullanıldığı yerler:** İletişim, Hakkımızda, Açılış sayfaları, Her sayfa
- **Okuduğu veri:** Shopify iletişim formu
- **Boyut:** 2 dosyada 36 KB, JavaScript yok
- **Lisans:** MIT, © 2026 Lintel
- **Sayfa:** https://lintelagency.com/tr/kaynaklar/shopify-bolumleri/iletisim-formu
- **Canlı demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-contact-form.html
- **Eklenme tarihi:** 2026-11-02

## Ne işe yarar

- Mağaza adresi, çalışma saatleri ve dükkân fotoğrafıyla İletişim sayfası
- Seçim listesi ve sipariş numarası alanıyla toptan satış ya da özel sipariş talep formu
- Hakkımızda ya da açılış sayfasının altında kısa bir "Bize sorun" formu

## Tema düzenleyici ayarları

Bölüm tema düzenleyicide “Lib · Contact form” 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 | Get in touch |  |
| `heading_tag` | `select` | Heading tag | h2 | `h1`, `h2`, `h3`, `p` |
| `heading_size` | `select` | Heading size | large | `small`, `medium`, `large`, `xlarge` |
| `text` | `richtext` | Text | `<p>Questions about an order, a product or a custom piece? Send us a note and we will reply by email.</p>` |  |

### Form fields

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `name_field` | `select` | Name field | required | `hidden`, `optional`, `required` |
| `phone_field` | `select` | Phone field | hidden | `hidden`, `optional`, `required` |
| `message_required` | `checkbox` | Message is required | `true` |  |

### Form text

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `name_label` | `text` | Name label | Name |  |
| `email_label` | `text` | Email label | Email |  |
| `phone_label` | `text` | Phone label | Phone |  |
| `message_label` | `text` | Message label | Message |  |
| `required_text` | `text` | Required field marker | (required) |  |
| `submit_label` | `text` | Send button | Send message |  |
| `success_message` | `text` | Message after sending | Thanks for writing. We will reply by email. |  |
| `error_heading` | `text` | Error summary heading | Please check the form: |  |
| `privacy_text` | `richtext` | Privacy note | `<p>We only use your details to answer you. Read our <a href="/policies/privacy-policy" title="Privacy policy">privacy policy</a>.</p>` |  |

### Info column

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `image` | `image_picker` | Desktop image | – |  |
| `image_mobile` | `image_picker` | Mobile image | – |  |
| `info_heading` | `text` | Heading | Visit the studio |  |

### Layout

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `info_position` | `select` | Info column on desktop | right | `right`, `left` |
| `mobile_order` | `select` | Order on mobile | form_first | `form_first`, `info_first` |
| `section_width` | `select` | Width | page | `page`, `full` |
| `text_alignment` | `select` | Heading alignment on desktop | left | `left`, `center` |
| `text_alignment_mobile` | `select` | Heading alignment on mobile | left | `left`, `center` |

### Colors

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Background | #FFFFFF |  |
| `color_bg_gradient` | `color_background` | Background gradient | – |  |
| `color_text` | `color` | Text | #1F1B17 |  |
| `color_accent` | `color` | Accent (button, focus, titles) | #7A5A3A |  |
| `color_accent_text` | `color` | Text on accent | #FFFFFF |  |
| `color_field` | `color` | Field background | #FFFFFF |  |
| `color_border` | `color` | Field border | #8A8178 |  |
| `color_panel` | `color` | Info column background | #F6F1EA |  |
| `color_error` | `color` | Errors | #B42318 |  |

### 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` | Fade in on scroll | `false` |  |

## Bloklar

Toplamda en fazla 12 blok.

### Extra field (`field`)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `label` | `text` | Label | Order number |  |
| `field_type` | `select` | Type | text | `text`, `textarea`, `select`, `checkbox` |
| `options` | `textarea` | Choices | – |  |
| `prompt` | `text` | First option text | Choose one |  |
| `checked_value` | `text` | Value when ticked | Yes |  |
| `unchecked_value` | `text` | Value when not ticked | No |  |
| `help` | `text` | Help text | – |  |
| `required` | `checkbox` | Required | `false` |  |
| `width` | `select` | Width on desktop | half | `half`, `full` |

### Address (`address`, en fazla 1)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `title` | `text` | Title | Address |  |
| `address` | `textarea` | Address | 14 Kiln Lane Portland, OR 97214 |  |
| `map_link_label` | `text` | Map link text | Open in Maps |  |
| `new_tab_text` | `text` | Screen reader text for the map link | (opens in a new tab) |  |

### Contact detail (`detail`)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `title` | `text` | Title | Email |  |
| `email` | `text` | Email address | – |  |
| `phone` | `text` | Phone number | – |  |
| `text` | `richtext` | Text | – |  |

## 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-contact-form.liquid` adında yeni bir dosya ekleyin, aşağıdaki kaynak koddan `sections/lib-contact-form.liquid` içeriğini yapıştırıp kaydedin.
4. `lib-image.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 · Contact form** 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-contact-form.liquid https://lintelagency.com/resources/shopify-sections/files/lib-contact-form.liquid
curl -fsSL -o snippets/lib-image.liquid https://lintelagency.com/resources/shopify-sections/files/lib-image.liquid
shopify theme push --theme <unpublished-theme-id> --only sections/lib-contact-form.liquid --only snippets/lib-image.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-contact-form.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-contact-form.liquid): `sections/` klasörüne
- [snippets/lib-image.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-image.liquid): `snippets/` klasörüne

## Sık sorulan sorular

### Mesajlar nereye gidiyor?

Temanızın kendi iletişim sayfasında olduğu gibi, Shopify yönetim panelinde Ayarlar > Bildirimler altında belirlenen gönderici e-posta adresine. Bölüm Shopify’ın iletişim formunu kullanır; uygulama ya da üçüncü taraf hizmet yoktur ve mağazanın spam koruması ayarları geçerli kalır.

### Kendi alanlarımı ekleyebilir miyim?

Evet. Ek alan blokları ekleyin: kısa metin, uzun metin, seçim listesi (her satıra bir seçenek) ya da onay kutusu; her birinde yardım satırı, zorunlu ya da isteğe bağlı seçimi ve yarım ya da tam genişlik vardır. Etiket, size gelen e-postada alanın adı olur.

### Erişilebilir mi?

Her alanın görünür bir etiketi vardır ve zorunlu işareti yalnızca yıldız değil, metindir. Gönderimden sonra hatalar alanların üstünde bir uyarı olarak listelenir, e-posta alanı geçersiz olarak işaretlenir ve başarı mesajı ekran okuyuculara duyurulur. Ad, e-posta ve telefon otomatik doldurmayı destekler.

### Harita bağlantısı bir harita API’si kullanıyor mu?

Hayır. Adres, onu yeni sekmede Google Haritalar’da açan düz bir bağlantıya dönüşür; sayfanıza hiçbir şey yüklenmez ve API anahtarı gerekmez. Gizlemek için bağlantı metnini boş bırakın.

## Kaynak kod

### sections/lib-contact-form.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  Contact form: Shopify's own contact form, so messages reach the store's sender email without an
  app. Name, email, phone and message are built in (phone optional, any of them can be required
  except email, which Shopify always needs), plus extra fields as blocks (text, long text, choice
  list, checkbox). Beside it an optional column with an image, address, a map link (no maps API),
  email, phone and opening hours. Errors are listed above the fields and tied to them. No JavaScript.
  Depends on: snippets/lib-image.liquid
{%- endcomment -%}

{%- liquid
  assign s = section.settings
  assign heading_tag = s.heading_tag | default: 'h2'
  assign form_id = 'LibContact-' | append: section.id
  assign info_count = 0
  for block in section.blocks
    if block.type == 'address' or block.type == 'detail'
      assign info_count = info_count | plus: 1
    endif
  endfor
  assign show_aside = false
  if s.image != blank or s.image_mobile != blank or s.info_heading != blank or info_count > 0
    assign show_aside = true
  endif
  assign name_required = false
  if s.name_field == 'required'
    assign name_required = true
  endif
  assign phone_required = false
  if s.phone_field == 'required'
    assign phone_required = true
  endif
  assign eager = false
  if section.index <= 2
    assign eager = true
  endif
-%}

{%- capture required_mark -%}
  <span class="lib-contact__required">{{ s.required_text | escape }}</span>
{%- endcapture -%}

<div
  class="lib-contact lib-contact--{{ s.section_width }}"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-aside="{% if show_aside %}{{ s.info_position }}{% else %}none{% endif %}"
  data-mobile-order="{{ s.mobile_order }}"
  {% 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-field: {{ s.color_field }};
    --lib-border: {{ s.color_border }};
    --lib-panel: {{ s.color_panel }};
    --lib-error: {{ s.color_error }};
    --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-contact__inner">
    <div class="lib-contact__main" data-align="{{ s.text_alignment }}" data-align-m="{{ s.text_alignment_mobile }}">
      {%- if s.heading != blank -%}
        <{{ heading_tag }} class="lib-contact__heading lib-contact__heading--{{ s.heading_size }}">
          {{- s.heading -}}
        </{{ heading_tag }}>
      {%- endif -%}
      {%- if s.text != blank -%}
        <div class="lib-contact__text">{{ s.text }}</div>
      {%- endif -%}

      {%- form 'contact', id: form_id, class: 'lib-contact__form' -%}
        {%- if form.posted_successfully? -%}
          <p class="lib-contact__msg lib-contact__msg--success" role="status" tabindex="-1" autofocus>
            <svg viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false">
              <path d="m5 10.5 3.2 3L15 6.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
            <span>{{ s.success_message | escape }}</span>
          </p>
        {%- elsif form.errors -%}
          <div class="lib-contact__msg lib-contact__msg--error" role="alert" tabindex="-1" autofocus>
            <p class="lib-contact__msg-title">{{ s.error_heading | escape }}</p>
            <ul role="list">
              {%- for field in form.errors -%}
                <li>
                  {%- if field == 'form' -%}
                    {{ form.errors.messages[field] }}
                  {%- else -%}
                    {{ form.errors.translated_fields[field] | capitalize }} {{ form.errors.messages[field] }}
                  {%- endif -%}
                </li>
              {%- endfor -%}
            </ul>
          </div>
        {%- endif -%}

        <div class="lib-contact__fields">
          {%- if s.name_field != 'hidden' -%}
            <div class="lib-contact__field lib-contact__field--half">
              <label class="lib-contact__label" for="{{ form_id }}-name">
                {{- s.name_label | escape -}}
                {%- if name_required %} {{ required_mark }}{% endif -%}
              </label>
              <input
                class="lib-contact__input"
                type="text"
                id="{{ form_id }}-name"
                name="contact[name]"
                value="{{ form.name | escape }}"
                autocomplete="name"
                {% if name_required %}
                  required aria-required="true"
                {% endif %}
              >
            </div>
          {%- endif -%}

          <div class="lib-contact__field lib-contact__field--half">
            <label class="lib-contact__label" for="{{ form_id }}-email">
              {{- s.email_label | escape }} {{ required_mark -}}
            </label>
            <input
              class="lib-contact__input"
              type="email"
              id="{{ form_id }}-email"
              name="contact[email]"
              value="{{ form.email | escape }}"
              autocomplete="email"
              autocapitalize="off"
              spellcheck="false"
              required
              aria-required="true"
              {% if form.errors contains 'email' %}
                aria-invalid="true"
              {% endif %}
            >
          </div>

          {%- if s.phone_field != 'hidden' -%}
            <div class="lib-contact__field lib-contact__field--half">
              <label class="lib-contact__label" for="{{ form_id }}-phone">
                {{- s.phone_label | escape -}}
                {%- if phone_required %} {{ required_mark }}{% endif -%}
              </label>
              <input
                class="lib-contact__input"
                type="tel"
                id="{{ form_id }}-phone"
                name="contact[phone]"
                value="{{ form.phone | escape }}"
                autocomplete="tel"
                {% if phone_required %}
                  required aria-required="true"
                {% endif %}
              >
            </div>
          {%- endif -%}

          {%- for block in section.blocks -%}
            {%- if block.type != 'field' -%}{%- continue -%}{%- endif -%}
            {%- assign b = block.settings -%}
            {%- if b.label == blank -%}{%- continue -%}{%- endif -%}
            {%- assign field_id = form_id | append: '-' | append: block.id -%}
            {%- assign field_name = 'contact[' | append: b.label | append: ']' -%}
            <div class="lib-contact__field lib-contact__field--{{ b.width }}" {{ block.shopify_attributes }}>
              {%- case b.field_type -%}
                {%- when 'checkbox' -%}
                  <div class="lib-contact__check">
                    <input type="hidden" name="{{ field_name | escape }}" value="{{ b.unchecked_value | escape }}">
                    <input
                      class="lib-contact__checkbox"
                      type="checkbox"
                      id="{{ field_id }}"
                      name="{{ field_name | escape }}"
                      value="{{ b.checked_value | escape }}"
                      {% if b.required %}
                        required aria-required="true"
                      {% endif %}
                    >
                    <label for="{{ field_id }}">
                      {{- b.label | escape -}}
                      {%- if b.required %} {{ required_mark }}{% endif -%}
                    </label>
                  </div>
                {%- when 'select' -%}
                  {%- assign choices = b.options | newline_to_br | split: '<br />' -%}
                  <label class="lib-contact__label" for="{{ field_id }}">
                    {{- b.label | escape -}}
                    {%- if b.required %} {{ required_mark }}{% endif -%}
                  </label>
                  <div class="lib-contact__select-wrap">
                    <select
                      class="lib-contact__input lib-contact__select"
                      id="{{ field_id }}"
                      name="{{ field_name | escape }}"
                      {% if b.required %}
                        required aria-required="true"
                      {% endif %}
                    >
                      <option value="">{{ b.prompt | escape }}</option>
                      {%- for choice in choices -%}
                        {%- assign choice = choice | strip -%}
                        {%- if choice != blank -%}
                          <option value="{{ choice | escape }}">{{ choice | escape }}</option>
                        {%- endif -%}
                      {%- endfor -%}
                    </select>
                    <svg class="lib-contact__chevron" viewBox="0 0 12 12" width="12" height="12" aria-hidden="true" focusable="false">
                      <path d="m2.5 4.5 3.5 3.5 3.5-3.5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                  </div>
                {%- when 'textarea' -%}
                  <label class="lib-contact__label" for="{{ field_id }}">
                    {{- b.label | escape -}}
                    {%- if b.required %} {{ required_mark }}{% endif -%}
                  </label>
                  <textarea
                    class="lib-contact__input lib-contact__textarea"
                    id="{{ field_id }}"
                    name="{{ field_name | escape }}"
                    rows="4"
                    {% if b.required %}
                      required aria-required="true"
                    {% endif %}
                  ></textarea>
                {%- else -%}
                  <label class="lib-contact__label" for="{{ field_id }}">
                    {{- b.label | escape -}}
                    {%- if b.required %} {{ required_mark }}{% endif -%}
                  </label>
                  <input
                    class="lib-contact__input"
                    type="text"
                    id="{{ field_id }}"
                    name="{{ field_name | escape }}"
                    {% if b.required %}
                      required aria-required="true"
                    {% endif %}
                  >
              {%- endcase -%}
              {%- if b.help != blank -%}
                <p class="lib-contact__help">{{ b.help | escape }}</p>
              {%- endif -%}
            </div>
          {%- endfor -%}

          <div class="lib-contact__field lib-contact__field--full">
            <label class="lib-contact__label" for="{{ form_id }}-body">
              {{- s.message_label | escape -}}
              {%- if s.message_required %} {{ required_mark }}{% endif -%}
            </label>
            <textarea
              class="lib-contact__input lib-contact__textarea"
              id="{{ form_id }}-body"
              name="contact[body]"
              rows="6"
              {% if s.message_required %}
                required aria-required="true"
              {% endif %}
            >{{ form.body }}</textarea>
          </div>
        </div>

        <div class="lib-contact__submit-row">
          <button type="submit" class="lib-contact__submit">{{ s.submit_label | escape }}</button>
          {%- if s.privacy_text != blank -%}
            <div class="lib-contact__privacy">{{ s.privacy_text }}</div>
          {%- endif -%}
        </div>
      {%- endform -%}
    </div>

    {%- if show_aside -%}
      <aside class="lib-contact__aside"{% if s.info_heading != blank %} aria-labelledby="{{ form_id }}-info"{% endif %}>
        {%- if s.image != blank or s.image_mobile != blank -%}
          <div class="lib-contact__media">
            {%- render 'lib-image',
              image: s.image,
              image_mobile: s.image_mobile,
              class: 'lib-contact__img',
              sizes: '(min-width: 990px) 40vw, 100vw',
              eager: eager
            -%}
          </div>
        {%- endif -%}
        <div class="lib-contact__info">
          {%- if s.info_heading != blank -%}
            <h3 class="lib-contact__info-heading" id="{{ form_id }}-info">{{ s.info_heading | escape }}</h3>
          {%- endif -%}
          {%- if info_count > 0 -%}
            <dl class="lib-contact__details">
              {%- for block in section.blocks -%}
                {%- assign b = block.settings -%}
                {%- case block.type -%}
                  {%- when 'address' -%}
                    {%- if b.address != blank -%}
                      <div {{ block.shopify_attributes }}>
                        <dt>{{ b.title | escape }}</dt>
                        <dd>
                          <address>{{ b.address | escape | newline_to_br }}</address>
                          {%- if b.map_link_label != blank -%}
                            {%- assign map_query = b.address | strip_newlines | url_encode -%}
                            <a class="lib-contact__map" href="https://www.google.com/maps/search/?api=1&amp;query={{ map_query }}" target="_blank" rel="noopener">
                              {{- b.map_link_label | escape -}}
                              <span class="lib-contact__sr"> {{ b.new_tab_text | escape }}</span>
                            </a>
                          {%- endif -%}
                        </dd>
                      </div>
                    {%- endif -%}
                  {%- when 'detail' -%}
                    {%- if b.email != blank or b.phone != blank or b.text != blank -%}
                      <div {{ block.shopify_attributes }}>
                        <dt>{{ b.title | escape }}</dt>
                        {%- if b.email != blank -%}
                          <dd><a href="mailto:{{ b.email | strip | escape }}">{{ b.email | strip | escape }}</a></dd>
                        {%- endif -%}
                        {%- if b.phone != blank -%}
                          {%- assign phone_href = b.phone | remove: ' ' | remove: '(' | remove: ')' | remove: '-' | remove: '.' -%}
                          <dd><a href="tel:{{ phone_href | escape }}">{{ b.phone | escape }}</a></dd>
                        {%- endif -%}
                        {%- if b.text != blank -%}
                          <dd class="lib-contact__rte">{{ b.text }}</dd>
                        {%- endif -%}
                      </div>
                    {%- endif -%}
                {%- endcase -%}
              {%- endfor -%}
            </dl>
          {%- endif -%}
        </div>
      </aside>
    {%- endif -%}
  </div>
</div>

{% stylesheet %}
  .lib-contact {
    --lib-radius: 10px;
    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-contact__inner {
    display: grid;
    gap: clamp(2rem, 5vw, 4.5rem);
    max-width: 1200px;
    margin: 0 auto;
  }
  .lib-contact--full .lib-contact__inner { max-width: none; }
  .lib-contact[data-aside='none'] .lib-contact__inner { max-width: 46rem; }
  .lib-contact__inner > * { min-width: 0; }
  @media (min-width: 990px) {
    .lib-contact[data-aside='right'] .lib-contact__inner { grid-template-columns: 3fr 2fr; }
    .lib-contact[data-aside='left'] .lib-contact__inner { grid-template-columns: 2fr 3fr; }
    .lib-contact[data-aside='left'] .lib-contact__aside { order: -1; }
  }
  @media (max-width: 749px) {
    .lib-contact { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); }
    .lib-contact[data-show='desktop'] { display: none; }
    .lib-contact[data-mobile-order='info_first'] .lib-contact__aside { order: -1; }
  }
  @media (min-width: 750px) {
    .lib-contact[data-show='mobile'] { display: none; }
  }

  .lib-contact__main[data-align='center'] :is(.lib-contact__heading, .lib-contact__text) { text-align: center; margin-inline: auto; }
  @media (max-width: 749px) {
    .lib-contact__main[data-align-m='left'] :is(.lib-contact__heading, .lib-contact__text) { text-align: left; margin-inline: 0; }
    .lib-contact__main[data-align-m='center'] :is(.lib-contact__heading, .lib-contact__text) { text-align: center; margin-inline: auto; }
  }
  .lib-contact__heading {
    margin: 0;
    font-size: clamp(2rem, 4vw, 3rem);
    line-height: 1.1;
    letter-spacing: -0.025em;
    text-wrap: balance;
  }
  .lib-contact__heading--small { font-size: clamp(1.5rem, 2.5vw, 2rem); }
  .lib-contact__heading--medium { font-size: clamp(1.75rem, 3vw, 2.5rem); }
  .lib-contact__heading--xlarge { font-size: clamp(2.5rem, 6vw, 4.25rem); }
  .lib-contact__text { margin-top: 1rem; max-width: 36rem; font-size: 1.0625rem; line-height: 1.65; opacity: 0.82; }
  .lib-contact__text > :first-child { margin-top: 0; }
  .lib-contact__text > :last-child { margin-bottom: 0; }
  .lib-contact__text a { color: inherit; text-underline-offset: 0.2em; }

  .lib-contact__form { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
  .lib-contact__fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.125rem 1rem; }
  .lib-contact__field { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 0.45rem; min-width: 0; }
  @media (min-width: 750px) {
    .lib-contact__field--half { grid-column: span 1; }
  }
  .lib-contact__label { font-size: 0.9375rem; font-weight: 600; }
  .lib-contact__required { font-weight: 400; opacity: 0.7; }
  .lib-contact__input {
    width: 100%;
    min-height: 3rem;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--lib-border);
    border-radius: var(--lib-radius);
    background: var(--lib-field);
    color: inherit;
    font: inherit;
    font-size: 1rem;
    line-height: 1.4;
  }
  .lib-contact__textarea { min-height: 8rem; resize: vertical; }
  .lib-contact__input:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; border-color: var(--lib-accent); }
  .lib-contact__input[aria-invalid='true'] { border-color: var(--lib-error); }
  .lib-contact__select-wrap { position: relative; }
  .lib-contact__select { appearance: none; padding-inline-end: 2.5rem; }
  .lib-contact__chevron { position: absolute; inset-inline-end: 1rem; top: 50%; transform: translateY(-50%); pointer-events: none; }
  .lib-contact__check { display: flex; align-items: flex-start; gap: 0.7rem; font-size: 0.9375rem; line-height: 1.45; }
  .lib-contact__checkbox { flex: none; width: 1.25rem; height: 1.25rem; margin: 0.1rem 0 0; accent-color: var(--lib-accent); }
  .lib-contact__checkbox:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; }
  .lib-contact__help { margin: 0; font-size: 0.8125rem; opacity: 0.72; }

  .lib-contact__submit-row { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; margin-top: 1.5rem; }
  .lib-contact__submit {
    min-height: 3rem;
    padding: 0.85rem 1.75rem;
    border: 0;
    border-radius: var(--lib-btn-radius, 999px);
    background: var(--lib-accent);
    color: var(--lib-accent-text);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
  }
  .lib-contact__submit:hover { transform: translateY(-1px); box-shadow: 0 8px 18px -10px rgb(0 0 0 / 0.45); }
  .lib-contact__submit:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 3px; }
  .lib-contact__privacy { flex: 1 1 16rem; font-size: 0.8125rem; line-height: 1.5; opacity: 0.75; }
  .lib-contact__privacy > * { margin: 0; }
  .lib-contact__privacy a { color: inherit; text-underline-offset: 0.2em; }

  .lib-contact__msg { display: flex; gap: 0.6rem; margin: 0 0 1.25rem; padding: 0.9rem 1rem; border-radius: var(--lib-radius); font-size: 0.9375rem; }
  .lib-contact__msg--success { align-items: center; background: color-mix(in srgb, var(--lib-accent) 12%, transparent); }
  .lib-contact__msg--error {
    flex-direction: column;
    gap: 0.35rem;
    border: 1px solid var(--lib-error);
    background: color-mix(in srgb, var(--lib-error) 8%, transparent);
  }
  .lib-contact__msg--error ul { margin: 0; padding-inline-start: 1.1rem; }
  .lib-contact__msg-title { margin: 0; font-weight: 600; }
  .lib-contact__msg svg { flex: none; }

  .lib-contact__aside {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: calc(var(--lib-radius) * 2);
    background: var(--lib-panel);
  }
  .lib-contact__media { aspect-ratio: 4 / 3; background: color-mix(in srgb, var(--lib-text) 6%, transparent); }
  .lib-contact__img { display: block; width: 100%; height: 100%; object-fit: cover; }
  .lib-contact__img:is(svg) { fill: color-mix(in srgb, var(--lib-text) 25%, transparent); }
  .lib-contact__info { padding: clamp(1.5rem, 3vw, 2.25rem); }
  .lib-contact__info-heading { margin: 0 0 1.25rem; font-size: 1.25rem; line-height: 1.3; }
  .lib-contact__details { display: grid; gap: 1.1rem; margin: 0; }
  .lib-contact__details dt {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--lib-accent);
  }
  .lib-contact__details dd { margin: 0.3rem 0 0; font-size: 0.9875rem; line-height: 1.55; }
  .lib-contact__details address { font-style: normal; }
  .lib-contact__details a { display: inline-block; padding-block: 0.15rem; color: inherit; text-underline-offset: 0.2em; overflow-wrap: anywhere; }
  .lib-contact__details a:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; }
  .lib-contact__map { margin-top: 0.35rem; font-weight: 600; }
  .lib-contact__details dd + dd { margin-top: 0.15rem; }
  .lib-contact__rte > * { margin: 0; }
  .lib-contact__rte > * + * { margin-top: 0.25rem; }
  .lib-contact__sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }

  @media (prefers-reduced-motion: reduce) {
    .lib-contact__submit { transition: none; }
    .lib-contact__submit:hover { transform: none; }
  }
  /* Motion: the form and the info column rise in as they scroll into view. */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .lib-contact[data-animate] .lib-contact__inner > * {
        animation: lib-contact-rise linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 45%;
      }
    }
  }
  @keyframes lib-contact-rise {
    from { opacity: 0; transform: translateY(20px); }
  }
{% endstylesheet %}

{% schema %}
{
  "name": "Lib · Contact form",
  "tag": "section",
  "class": "lib-section",
  "max_blocks": 12,
  "settings": [
    { "type": "header", "content": "Content" },
    { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Get in touch" },
    {
      "type": "select",
      "id": "heading_tag",
      "label": "Heading tag",
      "info": "Use H1 only when this is the page's main heading.",
      "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": "large"
    },
    { "type": "richtext", "id": "text", "label": "Text", "default": "<p>Questions about an order, a product or a custom piece? Send us a note and we will reply by email.</p>" },

    { "type": "header", "content": "Form fields" },
    { "type": "paragraph", "content": "Messages go to the sender email in Settings > Notifications. Email is always shown and required. Add more fields with Extra field blocks." },
    {
      "type": "select",
      "id": "name_field",
      "label": "Name field",
      "options": [
        { "value": "hidden", "label": "Hidden" },
        { "value": "optional", "label": "Optional" },
        { "value": "required", "label": "Required" }
      ],
      "default": "required"
    },
    {
      "type": "select",
      "id": "phone_field",
      "label": "Phone field",
      "options": [
        { "value": "hidden", "label": "Hidden" },
        { "value": "optional", "label": "Optional" },
        { "value": "required", "label": "Required" }
      ],
      "default": "hidden"
    },
    { "type": "checkbox", "id": "message_required", "label": "Message is required", "default": true },

    { "type": "header", "content": "Form text" },
    { "type": "text", "id": "name_label", "label": "Name label", "default": "Name" },
    { "type": "text", "id": "email_label", "label": "Email label", "default": "Email" },
    { "type": "text", "id": "phone_label", "label": "Phone label", "default": "Phone" },
    { "type": "text", "id": "message_label", "label": "Message label", "default": "Message" },
    { "type": "text", "id": "required_text", "label": "Required field marker", "default": "(required)" },
    { "type": "text", "id": "submit_label", "label": "Send button", "default": "Send message" },
    { "type": "text", "id": "success_message", "label": "Message after sending", "default": "Thanks for writing. We will reply by email." },
    { "type": "text", "id": "error_heading", "label": "Error summary heading", "default": "Please check the form:" },
    { "type": "richtext", "id": "privacy_text", "label": "Privacy note", "default": "<p>We only use your details to answer you. Read our <a href=\"/policies/privacy-policy\" title=\"Privacy policy\">privacy policy</a>.</p>" },

    { "type": "header", "content": "Info column" },
    { "type": "paragraph", "content": "Shown when it has an image, a heading or Address and Contact detail blocks." },
    { "type": "image_picker", "id": "image", "label": "Desktop image" },
    { "type": "image_picker", "id": "image_mobile", "label": "Mobile image", "info": "Optional. Shown below 750px." },
    { "type": "text", "id": "info_heading", "label": "Heading", "default": "Visit the studio" },

    { "type": "header", "content": "Layout" },
    {
      "type": "select",
      "id": "info_position",
      "label": "Info column on desktop",
      "options": [
        { "value": "right", "label": "Right" },
        { "value": "left", "label": "Left" }
      ],
      "default": "right"
    },
    {
      "type": "select",
      "id": "mobile_order",
      "label": "Order on mobile",
      "options": [
        { "value": "form_first", "label": "Form first" },
        { "value": "info_first", "label": "Info first" }
      ],
      "default": "form_first"
    },
    {
      "type": "select",
      "id": "section_width",
      "label": "Width",
      "options": [
        { "value": "page", "label": "Page width" },
        { "value": "full", "label": "Full width" }
      ],
      "default": "page"
    },
    {
      "type": "select",
      "id": "text_alignment",
      "label": "Heading alignment on desktop",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" }
      ],
      "default": "left"
    },
    {
      "type": "select",
      "id": "text_alignment_mobile",
      "label": "Heading alignment on mobile",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" }
      ],
      "default": "left"
    },

    { "type": "header", "content": "Colors" },
    { "type": "color", "id": "color_bg", "label": "Background", "default": "#FFFFFF" },
    { "type": "color_background", "id": "color_bg_gradient", "label": "Background gradient", "info": "Optional. Covers the background color." },
    { "type": "color", "id": "color_text", "label": "Text", "default": "#1F1B17" },
    { "type": "color", "id": "color_accent", "label": "Accent (button, focus, titles)", "default": "#7A5A3A" },
    { "type": "color", "id": "color_accent_text", "label": "Text on accent", "default": "#FFFFFF" },
    { "type": "color", "id": "color_field", "label": "Field background", "default": "#FFFFFF" },
    { "type": "color", "id": "color_border", "label": "Field border", "default": "#8A8178" },
    { "type": "color", "id": "color_panel", "label": "Info column background", "default": "#F6F1EA" },
    { "type": "color", "id": "color_error", "label": "Errors", "default": "#B42318" },

    { "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": "Fade in on scroll", "info": "Only in browsers that support scroll-driven animations; never when reduced motion is on.", "default": false }
  ],
  "blocks": [
    {
      "type": "field",
      "name": "Extra field",
      "settings": [
        { "type": "text", "id": "label", "label": "Label", "info": "Also the field's name in the email you receive.", "default": "Order number" },
        {
          "type": "select",
          "id": "field_type",
          "label": "Type",
          "options": [
            { "value": "text", "label": "Short text" },
            { "value": "textarea", "label": "Long text" },
            { "value": "select", "label": "Choice list" },
            { "value": "checkbox", "label": "Checkbox" }
          ],
          "default": "text"
        },
        { "type": "textarea", "id": "options", "label": "Choices", "info": "Choice list only. One per line.", "visible_if": "{{ block.settings.field_type == 'select' }}" },
        { "type": "text", "id": "prompt", "label": "First option text", "default": "Choose one", "visible_if": "{{ block.settings.field_type == 'select' }}" },
        { "type": "text", "id": "checked_value", "label": "Value when ticked", "default": "Yes", "visible_if": "{{ block.settings.field_type == 'checkbox' }}" },
        { "type": "text", "id": "unchecked_value", "label": "Value when not ticked", "default": "No", "visible_if": "{{ block.settings.field_type == 'checkbox' }}" },
        { "type": "text", "id": "help", "label": "Help text", "info": "Optional. Shown under the field." },
        { "type": "checkbox", "id": "required", "label": "Required", "default": false },
        {
          "type": "select",
          "id": "width",
          "label": "Width on desktop",
          "options": [
            { "value": "half", "label": "Half" },
            { "value": "full", "label": "Full" }
          ],
          "default": "half"
        }
      ]
    },
    {
      "type": "address",
      "name": "Address",
      "limit": 1,
      "settings": [
        { "type": "paragraph", "content": "Shown in the info column." },
        { "type": "text", "id": "title", "label": "Title", "default": "Address" },
        { "type": "textarea", "id": "address", "label": "Address", "default": "14 Kiln Lane\nPortland, OR 97214" },
        { "type": "text", "id": "map_link_label", "label": "Map link text", "info": "Opens the address in Google Maps. Leave empty to hide.", "default": "Open in Maps" },
        { "type": "text", "id": "new_tab_text", "label": "Screen reader text for the map link", "default": "(opens in a new tab)" }
      ]
    },
    {
      "type": "detail",
      "name": "Contact detail",
      "settings": [
        { "type": "paragraph", "content": "Shown in the info column: an email, a phone number, opening hours or any short note." },
        { "type": "text", "id": "title", "label": "Title", "default": "Email" },
        { "type": "text", "id": "email", "label": "Email address", "info": "Optional. Becomes a mailto link." },
        { "type": "text", "id": "phone", "label": "Phone number", "info": "Optional. Becomes a tap-to-call link." },
        { "type": "richtext", "id": "text", "label": "Text" }
      ]
    }
  ],
  "presets": [
    {
      "name": "Lib · Contact form",
      "blocks": [
        { "type": "field", "settings": { "label": "Order number", "help": "Optional. Helps us find your order faster." } },
        { "type": "address" },
        { "type": "detail", "settings": { "title": "Email", "email": "hello@example.com" } },
        { "type": "detail", "settings": { "title": "Opening hours", "text": "<p>Wed–Sat, 10:00–17:00</p>" } }
      ]
    }
  ]
}
{% endschema %}
```

### snippets/lib-image.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{% doc %}
  Responsive image with optional art direction: a separate mobile image (below 750px),
  each honouring its own focal point from the theme editor. Falls back to a placeholder.

  @param {image} [image] - Desktop image (also used on mobile when no mobile image is set)
  @param {image} [image_mobile] - Mobile image, below 750px
  @param {string} [class] - Class for the img element
  @param {string} [sizes] - sizes attribute for the desktop image (default 100vw)
  @param {boolean} [eager] - Load immediately with high fetch priority (use for the first sections on a page)
  @param {string} [placeholder] - placeholder_svg_tag name when no image is set (default 'lifestyle-1')

  @example
  {% render 'lib-image', image: section.settings.image, image_mobile: section.settings.image_mobile, class: 'lib-hero__img', sizes: '(min-width: 990px) 50vw, 100vw', eager: true %}
{% enddoc %}

{%- liquid
  assign desktop = image
  if desktop == blank
    assign desktop = image_mobile
  endif
  assign img_sizes = sizes | default: '100vw'
  assign img_loading = 'lazy'
  assign img_priority = 'auto'
  if eager
    assign img_loading = 'eager'
    assign img_priority = 'high'
  endif
  assign art = false
  if image != blank and image_mobile != blank
    assign art = true
  endif
-%}

{%- if desktop != blank -%}
  <picture
    class="lib-picture{% if art %} lib-picture--art{% endif %}"
    {% if art %}
      style="--lib-pos-m: {{ image_mobile.presentation.focal_point | default: '50% 50%' }};"
    {% endif %}
  >
    {%- if art -%}
      <source
        media="(max-width: 749px)"
        srcset="
          {{ image_mobile | image_url: width: 375 }} 375w,
          {{ image_mobile | image_url: width: 750 }} 750w,
          {{ image_mobile | image_url: width: 1100 }} 1100w,
          {{ image_mobile | image_url: width: 1500 }} 1500w
        "
        sizes="100vw"
        width="{{ image_mobile.width }}"
        height="{{ image_mobile.height }}"
      >
    {%- endif -%}
    {{
      desktop
      | image_url: width: 2400
      | image_tag:
        class: class,
        loading: img_loading,
        fetchpriority: img_priority,
        sizes: img_sizes,
        widths: '600, 900, 1200, 1600, 2000, 2400'
    }}
  </picture>
{%- else -%}
  {{ placeholder | default: 'lifestyle-1' | placeholder_svg_tag: class }}
{%- endif -%}

{% stylesheet %}
  .lib-picture { display: contents; }
  @media (max-width: 749px) {
    /* image_tag sets the desktop focal point inline; the mobile image needs its own. */
    .lib-picture--art img { object-position: var(--lib-pos-m) !important; }
  }
{% 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.
