# Press quotes: free Shopify section

> "As seen in" press quotes with each publication's logo, as quote cards or a rotator where the logos switch the quote. Pause button, no fake logos.

Press quotes is a free Shopify section for "as seen in" coverage: short quotes with each publication's logo or name, shown as a row of quote cards or as a rotator where the logos below switch the large quote. The rotator is built as accessible tabs, can rotate on its own with a pause button, stops while hovered or focused and never moves when reduced motion is on; without JavaScript every quote shows. Each quote can link to the article. Every quote, name and logo is yours to add, so use only coverage you actually received. Online Store 2.0, without an app.

- **Category:** Social proof and trust
- **Use on:** Home, About, Landing pages
- **Reads:** Content only
- **Size:** 21 KB in 1 file, with a small script
- **License:** MIT, © 2026 Lintel
- **Page:** https://lintelagency.com/resources/shopify-sections/press-quotes
- **Live demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-press-quotes.html
- **Added:** 2026-11-02

## What it’s for

- An "As seen in" strip on the home page after the hero
- Press coverage on an About or brand story page
- Launch landing pages that quote early reviews from magazines or blogs

## Editor settings

In the theme editor the section is called “Lib · Press quotes”. IDs, types, labels and defaults come from the section’s schema; the labels are what the theme editor shows.

### Content

| ID | Type | Label | Default | Options or range |
| --- | --- | --- | --- | --- |
| `heading` | `inline_richtext` | Heading | As seen in |  |
| `heading_tag` | `select` | Heading tag | h2 | `h1`, `h2`, `h3`, `p` |
| `heading_size` | `select` | Heading size | small | `small`, `medium`, `large` |
| `new_tab_label` | `text` | New tab notice (screen readers) | opens in a new tab |  |

### Layout

| ID | Type | Label | Default | Options or range |
| --- | --- | --- | --- | --- |
| `layout` | `select` | Layout | rotator | `grid`, `rotator` |
| `autoplay_seconds` | `range` | Rotate every (0 = off) | `6` | 0–12 s, step 1 |
| `tabs_label` | `text` | Logo list name (screen readers) | Publications |  |
| `pause_label` | `text` | Pause button label (screen readers) | Pause quotes |  |
| `play_label` | `text` | Play button label (screen readers) | Play quotes |  |
| `quote_size` | `select` | Quote size (cards) | medium | `small`, `medium`, `large` |
| `show_marks` | `checkbox` | Show quotation mark | `true` |  |
| `logo_height` | `range` | Logo height | `28` | 16–64 px, step 2 |
| `mono_logos` | `checkbox` | Show logos in grayscale | `true` |  |
| `section_width` | `select` | Width | page | `page`, `full` |
| `text_alignment` | `select` | Alignment on desktop | center | `left`, `center` |
| `text_alignment_mobile` | `select` | Alignment on mobile | center | `left`, `center` |

### Colors

| ID | Type | Label | Default | Options or range |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Background | #F5EFE6 |  |
| `color_bg_gradient` | `color_background` | Background gradient | – |  |
| `color_text` | `color` | Text | #1F1B17 |  |
| `color_accent` | `color` | Accent (quotation mark, selected logo) | #7A5A3A |  |
| `color_card` | `color` | Card background | #FFFFFF |  |

### Spacing and visibility

| ID | Type | Label | Default | Options or range |
| --- | --- | --- | --- | --- |
| `padding_top` | `range` | Top padding on desktop | `72` | 0–200 px, step 4 |
| `padding_bottom` | `range` | Bottom padding on desktop | `72` | 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

| ID | Type | Label | Default | Options or range |
| --- | --- | --- | --- | --- |
| `animate` | `checkbox` | Fade between quotes | `true` |  |

## Blocks

Up to 8 blocks in total.

### Quote (`quote`)

| ID | Type | Label | Default | Options or range |
| --- | --- | --- | --- | --- |
| `quote` | `richtext` | Quote | `<p>A short line the publication wrote about you.</p>` |  |
| `publication` | `text` | Publication | Publication |  |
| `logo` | `image_picker` | Logo | – |  |
| `link` | `url` | Link to the article | – |  |
| `new_tab` | `checkbox` | Open link in a new tab | `true` |  |

## Install

### In Shopify admin

1. Work on a copy, not your live theme: in Shopify admin go to **Online Store > Themes**, open the **…** menu on your current theme and choose **Duplicate**.
2. On the copy, open the **…** menu and choose **Edit code**.
3. In the `sections` folder, add a new file named `lib-press-quotes.liquid` and paste the contents of `sections/lib-press-quotes.liquid` from the source below. Save.
4. Open **Customize** on the copy, choose **Add section** and pick **Lib · Press quotes**. Replace the sample content with your own and set the colors.
5. Preview the copy, then publish it when it looks right.

### With Shopify CLI

From your local theme folder, download the files and push only them to an unpublished theme (find its ID with `shopify theme list`):

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

Never push to the live theme: always pass the ID of an unpublished theme and never use `--live` or `--allow-live`. Then add the section in the theme editor as above.

## Files

- [sections/lib-press-quotes.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-press-quotes.liquid): goes in `sections/`

## Questions

### Do the publication logos come with the section?

No. You upload each logo (or leave it empty to show the publication's name in text) and type the quote. The demo uses made-up publications. Show only coverage you received and logos you may use.

### Does the rotator move on its own?

Only if you set a time (1–12 seconds). Shoppers then get a pause button, rotation stops while the pointer or keyboard focus is on the quotes, and it never rotates when reduced motion is on, in line with WCAG 2.2.2.

### Can shoppers choose a quote themselves?

Yes. The logos are tabs: click or tap one, or use the arrow keys, Home and End, to show its quote. The selected logo is marked and announced to screen readers.

### Can quotes link to the article?

Yes. Add the article's URL to a quote; the logo or name becomes the link, optionally opening in a new tab with a screen-reader notice.

## Source

### sections/lib-press-quotes.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  Press quotes: short quotes from the press with each publication's logo (or its name), in a row
  of quote cards or as an "as seen in" rotator where the logos switch the quote. The rotator is a
  WAI-ARIA tabs pattern with optional autoplay that has a pause button, stops on hover and focus,
  and never runs when reduced motion is on. Without JavaScript every quote shows. Every quote,
  name and logo is the merchant's own: use only coverage you actually received.
  Depends on: nothing
{%- endcomment -%}

{%- liquid
  assign s = section.settings
  assign heading_tag = s.heading_tag | default: 'h2'
  assign rotator = false
  if s.layout == 'rotator' and section.blocks.size > 1
    assign rotator = true
  endif
-%}

<lib-press-quotes
  class="lib-press lib-press--{{ s.section_width }}"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-layout="{% if rotator %}rotator{% else %}grid{% endif %}"
  data-autoplay="{{ s.autoplay_seconds }}"
  {% if s.mono_logos %}
    data-mono
  {% endif %}
  {% 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-card: {{ s.color_card }};
    --lib-logo-h: {{ s.logo_height }}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-press__inner" data-align="{{ s.text_alignment }}" data-align-m="{{ s.text_alignment_mobile }}">
    {%- if s.heading != blank -%}
      <{{ heading_tag }} class="lib-press__heading lib-press__heading--{{ s.heading_size }}">
        {{- s.heading -}}
      </{{ heading_tag }}>
    {%- endif -%}

    <div class="lib-press__quotes">
      {%- for block in section.blocks -%}
        {%- assign b = block.settings -%}
        <figure class="lib-press__quote" id="LibPress-{{ block.id }}" data-panel {{ block.shopify_attributes }}>
          <blockquote class="lib-press__text lib-press__text--{{ s.quote_size }}">
            {%- if s.show_marks -%}<span class="lib-press__mark" aria-hidden="true">“</span>{%- endif -%}
            {{- b.quote -}}
          </blockquote>
          <figcaption class="lib-press__source">
            {%- capture source -%}
              {%- if b.logo != blank -%}
                {{ b.logo | image_url: width: 400 | image_tag: class: 'lib-press__logo', loading: 'lazy', alt: b.publication }}
              {%- else -%}
                <span class="lib-press__name">{{ b.publication | escape }}</span>
              {%- endif -%}
            {%- endcapture -%}
            {%- if b.link != blank -%}
              <a
                class="lib-press__link"
                href="{{ b.link }}"
                {% if b.new_tab %}
                  target="_blank" rel="noopener"
                {% endif %}
              >
                {{- source -}}
                {%- if b.new_tab and s.new_tab_label != blank -%}<span class="lib-press__sr"> ({{ s.new_tab_label | escape }})</span>{%- endif -%}
              </a>
            {%- else -%}
              {{- source -}}
            {%- endif -%}
          </figcaption>
        </figure>
      {%- endfor -%}
    </div>

    {%- if rotator -%}
      <div class="lib-press__controls" hidden data-controls>
        <div class="lib-press__tabs" role="tablist" aria-label="{{ s.tabs_label | escape }}">
          {%- for block in section.blocks -%}
            {%- assign b = block.settings -%}
            <button
              type="button"
              role="tab"
              class="lib-press__tab"
              id="LibPressTab-{{ block.id }}"
              aria-controls="LibPress-{{ block.id }}"
              aria-selected="{% if forloop.first %}true{% else %}false{% endif %}"
              {% unless forloop.first %}
                tabindex="-1"
              {% endunless %}
            >
              {%- if b.logo != blank -%}
                {{ b.logo | image_url: width: 400 | image_tag: class: 'lib-press__logo', loading: 'lazy', alt: b.publication }}
              {%- else -%}
                <span class="lib-press__name">{{ b.publication | escape }}</span>
              {%- endif -%}
            </button>
          {%- endfor -%}
        </div>
        {%- if s.autoplay_seconds > 0 -%}
          <button type="button" class="lib-press__pause" data-pause data-label-pause="{{ s.pause_label | escape }}" data-label-play="{{ s.play_label | escape }}" aria-label="{{ s.pause_label | escape }}">
            <svg class="lib-press__icon-pause" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false"><path d="M5 3.5v9M11 3.5v9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
            <svg class="lib-press__icon-play" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false"><path d="M5 3.5v9l7-4.5z" fill="currentColor"/></svg>
          </button>
        {%- endif -%}
      </div>
    {%- endif -%}
  </div>
</lib-press-quotes>

{% stylesheet %}
  .lib-press {
    display: block;
    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-press__inner { max-width: 1200px; margin: 0 auto; }
  .lib-press--full .lib-press__inner { max-width: none; }
  @media (max-width: 749px) {
    .lib-press { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); }
    .lib-press[data-show='desktop'] { display: none; }
  }
  @media (min-width: 750px) {
    .lib-press[data-show='mobile'] { display: none; }
  }

  .lib-press__heading {
    margin: 0 0 clamp(1.5rem, 3.5vw, 2.5rem);
    font-size: clamp(1.5rem, 2.6vw, 2.125rem);
    line-height: 1.15;
    letter-spacing: -0.02em;
  }
  .lib-press__heading--small { font-size: 0.875rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.75; }
  .lib-press__heading--large { font-size: clamp(2rem, 4vw, 3rem); }

  /* Grid: one card per quote. */
  .lib-press__quotes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: clamp(1rem, 2.5vw, 1.75rem);
  }
  .lib-press__quote {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 1.25rem;
    margin: 0;
    padding: clamp(1.25rem, 2.5vw, 1.75rem);
    border-radius: 14px;
    background: var(--lib-card);
  }
  .lib-press__text { margin: 0; font-size: clamp(1.0625rem, 1.5vw, 1.25rem); line-height: 1.45; text-wrap: pretty; }
  .lib-press__text--small { font-size: 1rem; }
  .lib-press__text--large { font-size: clamp(1.25rem, 2.2vw, 1.75rem); line-height: 1.35; letter-spacing: -0.01em; }
  .lib-press__text > p { display: inline; margin: 0; }
  .lib-press__mark { margin-right: 0.1em; color: var(--lib-accent); font-weight: 700; }
  .lib-press__source { display: flex; align-items: center; min-height: var(--lib-logo-h); }
  .lib-press__logo { display: block; width: auto; max-width: 10rem; height: var(--lib-logo-h); object-fit: contain; }
  .lib-press[data-mono] .lib-press__logo { filter: grayscale(1); opacity: 0.8; }
  .lib-press__name { font-family: Georgia, 'Times New Roman', serif; font-size: 1.0625rem; font-weight: 700; letter-spacing: 0.01em; }
  .lib-press__link { display: inline-flex; align-items: center; min-height: 2.75rem; color: inherit; text-decoration: none; }
  .lib-press__link:hover .lib-press__name { text-decoration: underline; text-underline-offset: 0.2em; }
  .lib-press__link:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 3px; border-radius: 4px; }
  .lib-press__sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Rotator: one large quote, the logos below switch it. */
  .lib-press[data-ready] .lib-press__quotes { display: block; }
  .lib-press[data-ready] .lib-press__quote {
    align-items: center;
    max-width: 52rem;
    margin-inline: auto;
    padding: 0;
    background: none;
    text-align: center;
  }
  .lib-press[data-ready] .lib-press__quote[hidden] { display: none; }
  .lib-press[data-ready] .lib-press__text { font-size: clamp(1.375rem, 2.8vw, 2rem); line-height: 1.3; letter-spacing: -0.01em; }
  .lib-press[data-ready] .lib-press__source { display: none; }
  .lib-press__controls { display: flex; align-items: center; justify-content: center; gap: 0.75rem; margin-top: clamp(1.5rem, 4vw, 2.5rem); }
  .lib-press__controls[hidden] { display: none; }
  .lib-press__tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem clamp(0.75rem, 3vw, 2rem); }
  .lib-press__tab {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    padding: 0.4rem 0.6rem;
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: inherit;
    font: inherit;
    opacity: 0.72;
    cursor: pointer;
    transition: opacity 0.2s ease, border-color 0.2s ease;
  }
  .lib-press__tab:hover { opacity: 0.9; }
  .lib-press__tab[aria-selected='true'] { opacity: 1; border-bottom-color: var(--lib-accent); }
  .lib-press__tab:focus-visible,
  .lib-press__pause:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; }
  .lib-press__pause {
    flex: none;
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    border: 1.5px solid color-mix(in srgb, var(--lib-text) 30%, transparent);
    border-radius: 50%;
    background: none;
    color: inherit;
    cursor: pointer;
  }
  .lib-press__pause .lib-press__icon-play,
  .lib-press__pause[data-paused] .lib-press__icon-pause { display: none; }
  .lib-press__pause[data-paused] .lib-press__icon-play { display: block; }

  .lib-press__inner[data-align='center'] .lib-press__heading { text-align: center; }
  .lib-press__inner[data-align='center'] .lib-press__quote { text-align: center; align-items: center; }
  @media (max-width: 749px) {
    .lib-press__inner[data-align-m='left'] .lib-press__heading { text-align: left; }
    .lib-press__inner[data-align-m='left'] .lib-press__quote { text-align: left; align-items: flex-start; }
    .lib-press__inner[data-align-m='center'] .lib-press__heading { text-align: center; }
    .lib-press__inner[data-align-m='center'] .lib-press__quote { text-align: center; align-items: center; }
  }

  @media (prefers-reduced-motion: no-preference) {
    .lib-press[data-animate][data-ready] .lib-press__quote:not([hidden]) { animation: lib-press-in 0.5s ease both; }
  }
  @media (prefers-reduced-motion: reduce) {
    .lib-press__tab { transition: none; }
  }
  @keyframes lib-press-in {
    from { opacity: 0; transform: translateY(6px); }
  }
{% endstylesheet %}

{% javascript %}
  (() => {
    if (customElements.get('lib-press-quotes')) return;
    const MS_PER_SECOND = 1000;

    class LibPressQuotes extends HTMLElement {
      connectedCallback() {
        const controls = this.querySelector('[data-controls]');
        if (!controls) return;
        this.tabs = [...controls.querySelectorAll('[role="tab"]')];
        this.panels = this.tabs.map((tab) => this.querySelector(`#${CSS.escape(tab.getAttribute('aria-controls'))}`));
        this.panels.forEach((panel, i) => {
          panel.setAttribute('role', 'tabpanel');
          panel.setAttribute('aria-labelledby', this.tabs[i].id);
        });
        controls.hidden = false;
        this.toggleAttribute('data-ready', true);
        this.index = 0;
        this.show(0, false);

        controls.addEventListener('click', (event) => {
          const tab = event.target.closest('[role="tab"]');
          if (tab) {
            this.stop(true);
            this.show(this.tabs.indexOf(tab), true);
          }
        });
        controls.addEventListener('keydown', (event) => {
          const current = this.tabs.indexOf(document.activeElement);
          if (current < 0) return;
          const moves = {ArrowRight: current + 1, ArrowLeft: current - 1, Home: 0, End: this.tabs.length - 1};
          if (!(event.key in moves)) return;
          event.preventDefault();
          this.stop(true);
          this.show((moves[event.key] + this.tabs.length) % this.tabs.length, true);
        });
        this.addEventListener('shopify:block:select', (event) => {
          const index = this.panels.findIndex((p) => p.id === `LibPress-${event.detail.blockId}`);
          if (index >= 0) {
            this.stop(true);
            this.show(index, false);
          }
        });

        this.seconds = Number(this.dataset.autoplay) || 0;
        this.pauseButton = this.querySelector('[data-pause]');
        const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
        if (this.seconds > 0 && !reduced && this.pauseButton) {
          this.pauseButton.addEventListener('click', () => (this.paused ? this.start() : this.stop(true)));
          // Hovering or focusing the quotes holds the rotation (WCAG 2.2.2) without unpausing a manual pause.
          ['mouseenter', 'focusin'].forEach((type) => this.addEventListener(type, () => this.hold(true)));
          ['mouseleave', 'focusout'].forEach((type) => this.addEventListener(type, () => this.hold(false)));
          this.start();
        } else {
          this.pauseButton?.remove();
        }
      }

      disconnectedCallback() {
        clearInterval(this.timer);
      }

      show(index, focus) {
        this.index = index;
        this.tabs.forEach((tab, i) => {
          const active = i === index;
          tab.setAttribute('aria-selected', String(active));
          tab.tabIndex = active ? 0 : -1;
          this.panels[i].hidden = !active;
        });
        if (focus) this.tabs[index].focus();
      }

      start() {
        this.paused = false;
        this.held = false;
        this.setPauseLabel();
        clearInterval(this.timer);
        this.timer = setInterval(() => {
          if (!this.held) this.show((this.index + 1) % this.tabs.length, false);
        }, this.seconds * MS_PER_SECOND);
      }

      stop(byUser) {
        clearInterval(this.timer);
        if (byUser) this.paused = true;
        this.setPauseLabel();
      }

      hold(value) {
        this.held = value;
      }

      setPauseLabel() {
        if (!this.pauseButton) return;
        const paused = Boolean(this.paused);
        this.pauseButton.toggleAttribute('data-paused', paused);
        this.pauseButton.setAttribute('aria-label', paused ? this.pauseButton.dataset.labelPlay : this.pauseButton.dataset.labelPause);
      }
    }
    customElements.define('lib-press-quotes', LibPressQuotes);
  })();
{% endjavascript %}

{% schema %}
{
  "name": "Lib · Press quotes",
  "tag": "section",
  "class": "lib-section",
  "max_blocks": 8,
  "settings": [
    { "type": "paragraph", "content": "Use only coverage you actually received, and logos you have the right to show." },
    { "type": "header", "content": "Content" },
    { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "As seen in" },
    {
      "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 (label)" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" }
      ],
      "default": "small"
    },
    { "type": "text", "id": "new_tab_label", "label": "New tab notice (screen readers)", "default": "opens in a new tab" },

    { "type": "header", "content": "Layout" },
    {
      "type": "select",
      "id": "layout",
      "label": "Layout",
      "options": [
        { "value": "grid", "label": "Quote cards" },
        { "value": "rotator", "label": "One quote, logos switch it" }
      ],
      "default": "rotator"
    },
    { "type": "range", "id": "autoplay_seconds", "label": "Rotate every (0 = off)", "info": "Rotator only. Shoppers get a pause button; never rotates when reduced motion is on.", "min": 0, "max": 12, "step": 1, "unit": "s", "default": 6 },
    { "type": "text", "id": "tabs_label", "label": "Logo list name (screen readers)", "default": "Publications" },
    { "type": "text", "id": "pause_label", "label": "Pause button label (screen readers)", "default": "Pause quotes" },
    { "type": "text", "id": "play_label", "label": "Play button label (screen readers)", "default": "Play quotes" },
    {
      "type": "select",
      "id": "quote_size",
      "label": "Quote size (cards)",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" }
      ],
      "default": "medium"
    },
    { "type": "checkbox", "id": "show_marks", "label": "Show quotation mark", "default": true },
    { "type": "range", "id": "logo_height", "label": "Logo height", "min": 16, "max": 64, "step": 2, "unit": "px", "default": 28 },
    { "type": "checkbox", "id": "mono_logos", "label": "Show logos in grayscale", "default": true },
    {
      "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": "Alignment on desktop",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" }
      ],
      "default": "center"
    },
    {
      "type": "select",
      "id": "text_alignment_mobile",
      "label": "Alignment on mobile",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" }
      ],
      "default": "center"
    },

    { "type": "header", "content": "Colors" },
    { "type": "color", "id": "color_bg", "label": "Background", "default": "#F5EFE6" },
    { "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 (quotation mark, selected logo)", "default": "#7A5A3A" },
    { "type": "color", "id": "color_card", "label": "Card background", "default": "#FFFFFF" },

    { "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": 72 },
    { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 72 },
    { "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 between quotes", "info": "Never when reduced motion is on.", "default": true }
  ],
  "blocks": [
    {
      "type": "quote",
      "name": "Quote",
      "settings": [
        { "type": "richtext", "id": "quote", "label": "Quote", "default": "<p>A short line the publication wrote about you.</p>" },
        { "type": "text", "id": "publication", "label": "Publication", "info": "Shown when there is no logo, and used as the logo's alt text.", "default": "Publication" },
        { "type": "image_picker", "id": "logo", "label": "Logo" },
        { "type": "url", "id": "link", "label": "Link to the article" },
        { "type": "checkbox", "id": "new_tab", "label": "Open link in a new tab", "default": true }
      ]
    }
  ],
  "presets": [
    {
      "name": "Lib · Press quotes",
      "blocks": [{ "type": "quote" }, { "type": "quote" }, { "type": "quote" }]
    }
  ]
}
{% endschema %}
```

## License

MIT License, © 2026 Lintel. Free to use, change and ship in your own store or in client work; keep the license line at the top of each file.
