Repository: canonical/vanilla-framework
Pull request #5464: feat(linked logo section) - Build Linked Logo Section pattern
Author: login: jmuzina
Labels: name: Review: QA +1
name: Review: Design +1
name: Feature 🎁
description: New feature or request
name: Review: Code +1 (with changes)
name: Review: Percy +1
Created: 2025-02-03T22:22:53Z | Merged: 2025-04-07T16:03:14Z

## Done

Builds the linked logo section pattern/HOC

Fixes [WD-17120](https://warthogs.atlassian.net/browse/WD-17120)

## QA

- Open demos: 
  - [default](https://vanilla-framework-5464.demos.haus/docs/examples/patterns/linked-logo-section/default?theme=light)
  - [50-50](https://vanilla-framework-5464.demos.haus/docs/examples/patterns/linked-logo-section/50-50?theme=light)
  - [25-75](https://vanilla-framework-5464.demos.haus/docs/examples/patterns/linked-logo-section/25-75?theme=light)
- Check against different screen sizes
- Review updated documentation:
  - https://vanilla-framework-5464.demos.haus/docs/patterns/linked-logo-section

### Check if PR is ready for release

If this PR contains Vanilla SCSS or macro code changes, it should contain the following changes to make sure it's ready for the release:

- [x] PR should have one of the following labels to automatically categorise it in release notes:
  - `Feature 🎁`, `Breaking Change 💣`, `Bug 🐛`, `Documentation 📝`, `Maintenance 🔨`.
- [ ] Vanilla version in `package.json` should be updated relative to the [most recent release](https://github.com/canonical/vanilla-framework/releases/latest), following semver convention
  - if existing APIs (CSS classes & macro APIs) are not changed it can be a bugfix release (x.x.**X**)
  - if existing APIs (CSS classes & macro APIs) are changed/added/removed it should be a minor version (x.**X**.0)
  - see the [wiki for more details](https://github.com/canonical/vanilla-framework/wiki/Release-process#pre-release-tasks)
- [ ] Any changes to component class names (new patterns, variants, removed or added features) or macros should be listed on the [what's new page](https://github.com/canonical/vanilla-framework/blob/main/releases.yml).


## Screenshots

![image](https://github.com/user-attachments/assets/503833ea-1e5c-4fd6-9939-87f9ca4d7166)
![image](https://github.com/user-attachments/assets/fe646687-2451-4a65-8fb8-5cd69f68fc0b)
![image](https://github.com/user-attachments/assets/4aece84b-923c-46b2-a2d1-e7881e6c5d3c)



[WD-17120]: https://warthogs.atlassian.net/browse/WD-17120?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ


Diff:
diff --git a/releases.yml b/releases.yml
index e2ad0e64b..c2d4dc0bc 100644
--- a/releases.yml
+++ b/releases.yml
@@ -4,6 +4,10 @@
       url: /docs/patterns/pricing-block
       status: New
       notes: We've introduced the new pricing block jinja pattern.
+    - component: Linked logo section
+      url: /docs/patterns/linked-logo-section
+      status: New
+      notes: We've introduced a new pattern for linked logo sections
 - version: 4.22.0
   features:
     - component: Icons / Heading, Quote
diff --git a/side-navigation.yaml b/side-navigation.yaml
index efcc1abf0..a2d97d034 100644
--- a/side-navigation.yaml
+++ b/side-navigation.yaml
@@ -125,6 +125,8 @@
       url: /docs/patterns/quote-wrapper
     - title: Pricing block
       url: /docs/patterns/pricing-block
+    - title: Linked logo section
+      url: /docs/patterns/linked-logo-section
 - heading: Utilities
   ordering: alphabetical
   subheadings:
diff --git a/templates/_macros/vf_linked-logo-section.jinja b/templates/_macros/vf_linked-logo-section.jinja
new file mode 100644
index 000000000..14d1512bf
--- /dev/null
+++ b/templates/_macros/vf_linked-logo-section.jinja
@@ -0,0 +1,75 @@
+{#
+  Params
+  - title_text (string) (required): The text to be displayed as the heading
+  - layout: layout of linked logo section. Options are '50/50', '25/75', 'full-width'
+  - links (array) (required) : Array of links, each including 'href', 'label', 'text', and 'image_html'
+#}
+
+{% macro vf_linked_logo_section(title_text, links, layout="full-width") -%}
+  {% set layout = layout | trim | replace('/', '-') %}
+
+  {% if layout not in ['50-50', '25-75', 'full-width'] %}
+    {% set layout = 'full-width' %}
+  {% endif %}
+
+  {% set max_logos_map = {
+    "full-width": 8,
+    "50-50": 6,
+    "25-75": 9
+  } %}
+
+  {% set max_logos = max_logos_map[layout] or 8 %}
+  {% set links = links[:max_logos] %}
+
+  {% macro _list(links, cols_per_item=2) %}
+    {%- if links|length > 1 -%}
+      <div class="grid-row">
+        {%- for link in links -%}
+          <div class="grid-col-{{ cols_per_item }} grid-col-medium-{{ cols_per_item }}">
+            <a href="{{ link.href }}" aria-label="{{ link.label }}">
+              <div class="p-image-container--16-9 is-highlighted">
+                {{ link.image_html | safe }}
+              </div>
+              <hr class="p-rule--muted">
+              <p>{{ link.text }}</p>
+            </a>
+          </div>
+        {%- endfor -%}
+      </div>
+    {%- endif -%}
+  {% endmacro %}
+
+  <section class="p-section">
+    <hr class="p-rule is-fixed-width"/>
+    {%- if layout == "50-50" -%}
+      <div class="p-section--shallow">
+        <div class="grid-row">
+          <div class="grid-col-4">
+            <h2>{{ title_text }}</h2>
+          </div>
+          <div class="grid-col-4 grid-col-medium-4">
+            {{ _list(links) }}
+          </div>
+        </div>
+      </div>
+    {%- elif layout == "25-75" -%}
+      <div class="p-section--shallow">
+        <div class="grid-row">
+          <div class="grid-col-2">
+            <h2>{{ title_text }}</h2>
+          </div>
+          <div class="grid-col-6">
+            {{ _list(links) }}
+          </div>
+        </div>
+      </div>
+    {%- else -%}
+      <div class="p-section--shallow">
+        <div class="grid-row">
+          <h2>{{- title_text -}}</h2>
+        </div>
+      </div>
+      {{ _list(links) }}
+    {%- endif -%}
+  </section>
+{%- endmacro %}
diff --git a/templates/docs/examples/patterns/linked-logo-section/25-75.html b/templates/docs/examples/patterns/linked-logo-section/25-75.html
new file mode 100644
index 000000000..921f27e57
--- /dev/null
+++ b/templates/docs/examples/patterns/linked-logo-section/25-75.html
@@ -0,0 +1,71 @@
+{% extends "_layouts/examples.html" %}
+{% from "_macros/vf_linked-logo-section.jinja" import vf_linked_logo_section %}
+
+{% block title %}Linked Logo Section / 25/75{% endblock %}
+{% block standalone_css %}patterns_all{% endblock %}
+
+{% block content %}
+
+{{ vf_linked_logo_section(
+  title_text="PostgreSQL, security and support",
+  layout="25/75",
+  links=[
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Kubeflow",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/cd89477e-kubeflow-logo-container-vert-fill.png" alt="" width="432" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MLflow",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png" alt="" width="222" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Apache Spark",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png" alt="" width="240" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "OpenSearch",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/a8185f91-opensearch-logo-container-vert-fill.png" alt="" width="330" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Kafka",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/d30de1f1-kafka-logo-container-vert-fill.png" alt="" width="294" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "PostgreSQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/f5605b7e-postgre-sql-container-vert-fill.png" alt="" width="432" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MongoDB",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/efdc8292-mongodb-logo-container-vert-fill.png" alt="" width="413" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MySQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/692e2b1d-mysql-logo-container-vert-fill.png" alt="" width="300" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MySQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/692e2b1d-mysql-logo-container-vert-fill.png" alt="" width="300" height="481" />'
+    },
+  ],
+) }}
+
+
+{% endblock %}
diff --git a/templates/docs/examples/patterns/linked-logo-section/50-50.html b/templates/docs/examples/patterns/linked-logo-section/50-50.html
new file mode 100644
index 000000000..55cd0cb9b
--- /dev/null
+++ b/templates/docs/examples/patterns/linked-logo-section/50-50.html
@@ -0,0 +1,53 @@
+{% extends "_layouts/examples.html" %}
+{% from "_macros/vf_linked-logo-section.jinja" import vf_linked_logo_section %}
+
+{% block title %}Linked Logo Section / 50/50{% endblock %}
+{% block standalone_css %}patterns_all{% endblock %}
+
+{% block content %}
+
+{{ vf_linked_logo_section(
+  title_text="Come for PostgreSQL, get security and support for your entire stack",
+  layout="50/50",
+  links=[
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Kubeflow",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/cd89477e-kubeflow-logo-container-vert-fill.png" alt="" width="432" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MLflow",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png" alt="" width="222" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Apache Spark",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png" alt="" width="240" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "OpenSearch",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/a8185f91-opensearch-logo-container-vert-fill.png" alt="" width="330" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Kafka",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/d30de1f1-kafka-logo-container-vert-fill.png" alt="" width="294" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "PostgreSQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/f5605b7e-postgre-sql-container-vert-fill.png" alt="" width="432" height="481" />'
+    },
+  ],
+) }}
+
+
+{% endblock %}
diff --git a/templates/docs/examples/patterns/linked-logo-section/combined.html b/templates/docs/examples/patterns/linked-logo-section/combined.html
new file mode 100644
index 000000000..d3643c985
--- /dev/null
+++ b/templates/docs/examples/patterns/linked-logo-section/combined.html
@@ -0,0 +1,12 @@
+{% extends "_layouts/examples.html" %}
+{% block title %}Linked Logo Section / Combined {% endblock %}
+
+{% block standalone_css %}patterns_all{% endblock %}
+
+{% block content %}
+{% with is_combined = true %}
+  <section>{% include 'docs/examples/patterns/linked-logo-section/default.html' %}</section>
+  <section>{% include 'docs/examples/patterns/linked-logo-section/25-75.html' %}</section>
+  <section>{% include 'docs/examples/patterns/linked-logo-section/50-50.html' %}</section>
+{% endwith %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/docs/examples/patterns/linked-logo-section/default.html b/templates/docs/examples/patterns/linked-logo-section/default.html
new file mode 100644
index 000000000..81c88f03e
--- /dev/null
+++ b/templates/docs/examples/patterns/linked-logo-section/default.html
@@ -0,0 +1,76 @@
+{% extends "_layouts/examples.html" %}
+{% from "_macros/vf_linked-logo-section.jinja" import vf_linked_logo_section %}
+
+{% block title %}Linked Logo Section / Default{% endblock %}
+{% block standalone_css %}patterns_all{% endblock %}
+
+{% block content %}
+
+{{ vf_linked_logo_section(
+  title_text="Come for PostgreSQL, get security and support for your entire stack",
+  links=[
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Kubeflow",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/cd89477e-kubeflow-logo-container-vert-fill.png" alt="" width="432" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MLflow",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png" alt="" width="222" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Apache Spark",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png" alt="" width="240" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "OpenSearch",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/a8185f91-opensearch-logo-container-vert-fill.png" alt="" width="330" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "Kafka",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/d30de1f1-kafka-logo-container-vert-fill.png" alt="" width="294" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "PostgreSQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/f5605b7e-postgre-sql-container-vert-fill.png" alt="" width="432" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MongoDB",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/efdc8292-mongodb-logo-container-vert-fill.png" alt="" width="413" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MySQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/692e2b1d-mysql-logo-container-vert-fill.png" alt="" width="300" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MySQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/692e2b1d-mysql-logo-container-vert-fill.png" alt="" width="300" height="481" />'
+    },
+    {
+      "href": "#",
+      "text": "Learn more &rsaquo;",
+      "label": "MySQL",
+      "image_html": '<img class="p-image-container__image" src="https://assets.ubuntu.com/v1/692e2b1d-mysql-logo-container-vert-fill.png" alt="" width="300" height="481" />'
+    }
+  ],
+) }}
+
+
+{% endblock %}
diff --git a/templates/docs/patterns/linked-logo-section/index.md b/templates/docs/patterns/linked-logo-section/index.md
new file mode 100644
index 000000000..f71a381a9
--- /dev/null
+++ b/templates/docs/patterns/linked-logo-section/index.md
@@ -0,0 +1,212 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                           | Description                                                                               |
+| --------------------------------- | ----------------------------------------------------------------------------------------- |
+| title_text (**required**)         | `H2` title text.                                                                          |
+| Layout                            | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits. |
+| Links (**required**)              | An `Array<Object>` of individual image link properties.                                   |
+| Links[].href (**required**)       | The target link for the logo.                                                             |
+| Links[].text (**required**)       | The link text for the logo.                                                               |
+| Links[].label (**required**)      | The `aria-label` for the logo.                                                            |
+| Links[].image_html (**required**) | The logo image element.                                                                   |
+
+## Full width
+
+This is the default layout for this pattern and can be used with a maximum of 8 logos.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-width</code>
+          </td>
+          <td>
+            The intended grid layout for the section.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            Array
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Array of image links.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].href</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Target link for the image.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Logo link text.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].label</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            <code>aria-label</code> for the logo link. This attribute is added to the wrapping `a` tag under the hood and it is this label that screenreaders will read. Additional alt text added to the image element will be ignored by assistive techology and as such can be set to null.   
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].image_html</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            HTMLImageElement
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Logo image element. This can be defined using raw HTML or using the <a href="https://github.com/canonical/canonicalwebteam.image-template/">Canonical image-template module</a>. Regardless of how this is initialized, it will need to include the <code>p-image-container__image</code> CSS class to comply with the <a href="/docs/patterns/images#highlighted-image">Highlighted image pattern</a> which wraps each link item under the hood. 
+          </td>
+        </tr>
+      </tbody>
+    </thead>
+  </table>
+</div>
+
+## Import
+
+### Jinja Macro
+
+To import the Linked Logo section Jinja macro, copy the following import statement into your
+Jinja template.
+
+```jinja
+{% raw -%}
+{% from "_macros/vf_linked-logo-section.jinja" import vf_linked_logo_section %}
+{%- endraw -%}
+```
+
+View the [building with Jinja macros guide](/docs/building-vanilla#jinja-macros)
+for macro installation instructions.
+
+### SCSS
+
+Since Patterns leverage many other parts of Vanilla in their composition and content, we
+recommend [importing the entirety of Vanilla](/docs#install) for full support.


Reviews:
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:30:10Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:34:33Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:35:38Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:41:55Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-03T16:00:36Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-03T16:02:19Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-03T16:13:04Z
user: login: jmuzina
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-03T16:15:00Z
user: login: mtruj013
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T08:04:56Z
user: login: advl
body: Approved with thanks
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:01:51Z

Review comments:
diff_hunk: @@ -0,0 +1,161 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                   | Description                                                                                            |
+| ------------------------- | ------------------------------------------------------------------------------------------------------ |
+| title_text (**required**) | `H2` title text.                                                                                       |
+| Links (**required**)      | A list of image links containing four fields for each link: `href`, `text`, `label`, and `image_html`. |
+| Layout                    | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits.              |
+
+### Image variations and considerations
+
+The `image_html` field can be defined using raw html or using the [Canonical image-template module](https://github.com/canonical/canonicalwebteam.image-template/tree/6ebd34c5967f69ac23c97a24bcf6bd703a1ab7ce) as in the following link example:
+
+<pre>
+  {
+    "href": "#",
+    "text": "Learn more&nbsp;&rsaquo;",
+    "label": "MLflow",
+    "image_html": image(url="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png",
+      alt="",
+      width="222",
+      height="481",
+      hi_def=True,
+      loading="auto",
+      attrs={"class": "p-image-container__image"}
+    ) | safe
+  },
+</pre>
+
+#### Image containers
+
+Each image is wrapped in a [highlighted image container](/docs/patterns/images#highlighted-image) under the hood. To make correct use of this component the `p-image-container__image` class should be added to each to each image.
+
+### Accessibility
+
+Each image in this component is wrapped by an `a` tag which includes an `aria-label` defined in the `label` field. Therefore, this is the label screenreaders will read, `alt` text added to the image itself will be ignored by assistive techjonology.
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
+          </td>
+          <td>
+            The intented grid layout for the section.
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: Typo
```suggestion
            The intended grid layout for the section.
```
created_at: 2025-04-02T14:24:22Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,161 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                   | Description                                                                                            |
+| ------------------------- | ------------------------------------------------------------------------------------------------------ |
+| title_text (**required**) | `H2` title text.                                                                                       |
+| Links (**required**)      | A list of image links containing four fields for each link: `href`, `text`, `label`, and `image_html`. |
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: I'd suggest aligning this with the [pricing block documentation](https://staging.vanillaframework.io/docs/patterns/pricing-block) which spells out the attributes of the `links` elements explicitly like this

```
Tiers[].Name (required)
Tiers[].Price (required)
```
etc. This makes it a bit clearer which attributes must be passed to each element. Thanks @petesfrench for establishing this :)
created_at: 2025-04-02T14:26:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,161 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                   | Description                                                                                            |
+| ------------------------- | ------------------------------------------------------------------------------------------------------ |
+| title_text (**required**) | `H2` title text.                                                                                       |
+| Links (**required**)      | A list of image links containing four fields for each link: `href`, `text`, `label`, and `image_html`. |
+| Layout                    | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits.              |
+
+### Image variations and considerations
+
+The `image_html` field can be defined using raw html or using the [Canonical image-template module](https://github.com/canonical/canonicalwebteam.image-template/tree/6ebd34c5967f69ac23c97a24bcf6bd703a1ab7ce) as in the following link example:
+
+<pre>
+  {
+    "href": "#",
+    "text": "Learn more&nbsp;&rsaquo;",
+    "label": "MLflow",
+    "image_html": image(url="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png",
+      alt="",
+      width="222",
+      height="481",
+      hi_def=True,
+      loading="auto",
+      attrs={"class": "p-image-container__image"}
+    ) | safe
+  },
+</pre>
+
+#### Image containers
+
+Each image is wrapped in a [highlighted image container](/docs/patterns/images#highlighted-image) under the hood. To make correct use of this component the `p-image-container__image` class should be added to each to each image.
+
+### Accessibility
+
+Each image in this component is wrapped by an `a` tag which includes an `aria-label` defined in the `label` field. Therefore, this is the label screenreaders will read, `alt` text added to the image itself will be ignored by assistive techjonology.
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
+          </td>
+          <td>
+            The intented grid layout for the section.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            Array
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Array of image links, each including <code>href</code>, <code>label</code>, <code>text</code>, and <code>image_html</code> fields.
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: I would also align this with the [pricing block](https://staging.vanillaframework.io/docs/patterns/pricing-block#jinja-macro) so we have a row for each image attribute
created_at: 2025-04-02T14:28:48Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,161 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                   | Description                                                                                            |
+| ------------------------- | ------------------------------------------------------------------------------------------------------ |
+| title_text (**required**) | `H2` title text.                                                                                       |
+| Links (**required**)      | A list of image links containing four fields for each link: `href`, `text`, `label`, and `image_html`. |
+| Layout                    | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits.              |
+
+### Image variations and considerations
+
+The `image_html` field can be defined using raw html or using the [Canonical image-template module](https://github.com/canonical/canonicalwebteam.image-template/tree/6ebd34c5967f69ac23c97a24bcf6bd703a1ab7ce) as in the following link example:
+
+<pre>
+  {
+    "href": "#",
+    "text": "Learn more&nbsp;&rsaquo;",
+    "label": "MLflow",
+    "image_html": image(url="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png",
+      alt="",
+      width="222",
+      height="481",
+      hi_def=True,
+      loading="auto",
+      attrs={"class": "p-image-container__image"}
+    ) | safe
+  },
+</pre>
+
+#### Image containers
+
+Each image is wrapped in a [highlighted image container](/docs/patterns/images#highlighted-image) under the hood. To make correct use of this component the `p-image-container__image` class should be added to each to each image.
+
+### Accessibility
+
+Each image in this component is wrapped by an `a` tag which includes an `aria-label` defined in the `label` field. Therefore, this is the label screenreaders will read, `alt` text added to the image itself will be ignored by assistive techjonology.
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
+          </td>
+          <td>
+            The intented grid layout for the section.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            Array
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Array of image links, each including <code>href</code>, <code>label</code>, <code>text</code>, and <code>image_html</code> fields.
+          </td>
+        </tr>
+      </tbody>
+    </thead>
+  </table>
+</div>
+
+## Import
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: We like to also include a note about including all of Vanilla's scss in these sections, see Hero for example:
https://vanillaframework.io/docs/patterns/hero#import
created_at: 2025-04-02T14:29:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,161 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                   | Description                                                                                            |
+| ------------------------- | ------------------------------------------------------------------------------------------------------ |
+| title_text (**required**) | `H2` title text.                                                                                       |
+| Links (**required**)      | A list of image links containing four fields for each link: `href`, `text`, `label`, and `image_html`. |
+| Layout                    | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits.              |
+
+### Image variations and considerations
+
+The `image_html` field can be defined using raw html or using the [Canonical image-template module](https://github.com/canonical/canonicalwebteam.image-template/tree/6ebd34c5967f69ac23c97a24bcf6bd703a1ab7ce) as in the following link example:
+
+<pre>
+  {
+    "href": "#",
+    "text": "Learn more&nbsp;&rsaquo;",
+    "label": "MLflow",
+    "image_html": image(url="https://assets.ubuntu.com/v1/104192d9-mlflow-logo-container-vert-fill.png",
+      alt="",
+      width="222",
+      height="481",
+      hi_def=True,
+      loading="auto",
+      attrs={"class": "p-image-container__image"}
+    ) | safe
+  },
+</pre>
+
+#### Image containers
+
+Each image is wrapped in a [highlighted image container](/docs/patterns/images#highlighted-image) under the hood. To make correct use of this component the `p-image-container__image` class should be added to each to each image.
+
+### Accessibility
+
+Each image in this component is wrapped by an `a` tag which includes an `aria-label` defined in the `label` field. Therefore, this is the label screenreaders will read, `alt` text added to the image itself will be ignored by assistive techjonology.
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
+          </td>
+          <td>
+            The intented grid layout for the section.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            Array
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Array of image links, each including <code>href</code>, <code>label</code>, <code>text</code>, and <code>image_html</code> fields.
+          </td>
+        </tr>
+      </tbody>
+    </thead>
+  </table>
+</div>
+
+## Import
+
+### Jinja Macro
+
+To import the Linked Logo section Jinja macro, copy the following import statement into your
+Jinja template.
+
+```jinja
+{% raw -%}
+{% from "_macros/vf_linked_logo_section.jinja" import vf_linked_logo_section %}
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: Typo in the file name, this would cause an import error if someone copied it
```suggestion
{% from "_macros/vf_linked-logo-section.jinja" import vf_linked_logo_section %}
```
created_at: 2025-04-02T14:29:58Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,75 @@
+{#
+  Params
+  - title_text (string) (required): The text to be displayed as the heading
+  - layout: layout of linked logo section. Options are '50/50', '25/75', 'full-width'
+  - links (array) (required) : Array of links, each including 'href', 'label', 'text', and 'image_html'
+#}
+
+{% macro vf_linked_logo_section(title_text, links, layout="full-width") -%}
path: templates/_macros/vf_linked-logo-section.jinja
user: login: jmuzina
body: I'd suggest having a look at whitespace controls inside this macro if you have some time. There is some extra whitespace between some of the lines in the HTML rendered by this macro:

<img width="399" alt="Screenshot 2025-04-02 at 10 31 03" src="https://github.com/user-attachments/assets/9dc4cd6b-23b0-44b2-a19d-553231199aa9" />

It's not really that egregious though, so I'd consider fixing this a "nice-to-have" as people will primarily be consuming via macro.

To test out how the HTML is rendered, use the language switcher at the top right of an example iframe to switch to HTML
<img width="399" alt="Screenshot 2025-04-02 at 10 33 43" src="https://github.com/user-attachments/assets/62532cfb-1b85-4f34-8a62-63c7724e53ad" />

created_at: 2025-04-02T14:34:33Z
author_association: MEMBER
path: templates/docs/examples/patterns/linked-logo-section/_shared-context.jinja
user: login: jmuzina
body: As you've un-extracted the shared list items, you can delete this file and remove its import from all of the examples
created_at: 2025-04-02T14:35:37Z
author_association: MEMBER
path: templates/docs/examples/patterns/linked-logo-section/default.html
user: login: jmuzina
body: Can you please create a `combined.html` file in this directory, which embeds the other examples for the linked logo section? This helps us reduce Percy snapshot usage.

Ex: [here](https://github.com/canonical/vanilla-framework/blob/760dba992a797dfcd8bf2bcc47415c8e3181e279/templates/docs/examples/patterns/hero/combined.html)
created_at: 2025-04-02T14:41:55Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,210 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                           | Description                                                                               |
+| --------------------------------- | ----------------------------------------------------------------------------------------- |
+| title_text (**required**)         | `H2` title text.                                                                          |
+| Layout                            | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits. |
+| Links (**required**)              | An `Array<Object>` of individual image link properties.                                   |
+| Links[].href (**required**)       | The target link for the logo.                                                             |
+| Links[].text (**required**)       | The link text for the logo.                                                               |
+| Links[].label (**required**)      | The `aria-label` for the logo.                                                            |
+| Links[].image_html (**required**) | The logo image element.                                                                   |
+
+## Full width
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: In the 50/50 and 25/75 sections, you noted the max number of logos per variant, but you haven't noted that here. It's worth nothing here that the full width variant can accept  8 logos.
created_at: 2025-04-03T16:00:36Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,210 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                           | Description                                                                               |
+| --------------------------------- | ----------------------------------------------------------------------------------------- |
+| title_text (**required**)         | `H2` title text.                                                                          |
+| Layout                            | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits. |
+| Links (**required**)              | An `Array<Object>` of individual image link properties.                                   |
+| Links[].href (**required**)       | The target link for the logo.                                                             |
+| Links[].text (**required**)       | The link text for the logo.                                                               |
+| Links[].label (**required**)      | The `aria-label` for the logo.                                                            |
+| Links[].image_html (**required**) | The logo image element.                                                                   |
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
+          </td>
+          <td>
+            The intended grid layout for the section.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            Array
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Array of image links.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].href</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Target link for the image.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Logo link text.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].label</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            <code>aria-label</code> for the logo link. This attribute is added to the wrapping `a` tag under the hood and it is this label that screenreaders will read. Additional alt text added to the image element will be ignored by assistive techology and as such can be set to null.   
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].image_html</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            HTMLImageElement
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Logo image element. This can be defined using raw HTML or using the <a href="https://github.com/canonical/canonicalwebteam.image-template/">Canonical image-template module</a>. Regardless of how this is initialized, it will need to include the <code>p-image-container__image</code> to comply with the <a href="/docs/patterns/images#highlighted-image">Highlighted image pattern</a> which wraps each link item under the hood. 
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: "include p-image-container__image" is ambiguous, I would mention specifically this is a CSS class.
created_at: 2025-04-03T16:02:19Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,210 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                           | Description                                                                               |
+| --------------------------------- | ----------------------------------------------------------------------------------------- |
+| title_text (**required**)         | `H2` title text.                                                                          |
+| Layout                            | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits. |
+| Links (**required**)              | An `Array<Object>` of individual image link properties.                                   |
+| Links[].href (**required**)       | The target link for the logo.                                                             |
+| Links[].text (**required**)       | The link text for the logo.                                                               |
+| Links[].label (**required**)      | The `aria-label` for the logo.                                                            |
+| Links[].image_html (**required**) | The logo image element.                                                                   |
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
path: templates/docs/patterns/linked-logo-section/index.md
user: login: jmuzina
body: typo
```suggestion
            <code>full-width</code>
```
created_at: 2025-04-03T16:13:04Z
author_association: MEMBER
diff_hunk: @@ -1,3 +1,9 @@
+- version: 4.24.0
+  features:
+    - component: Linked logo section
+      url: /docs/patterns/linked-logo-section
+      status: New
+      notes: We've introduced a new pattern for linked logo sections
path: releases.yml
user: login: jmuzina
body: Can you move this into 4.23.0, underneath pricing block? It's looking like they will release together
created_at: 2025-04-03T16:15:00Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,210 @@
+---
+wrapper_template: '_layouts/docs.html'
+context:
+  title: Linked logo section | Patterns
+---
+
+{% from "docs/macros/patterns/wip-notice.jinja" import pattern_wip_notice %}
+
+{{- pattern_wip_notice() }}
+
+A linked logo section is used to display a list of logos which explicitly link to additional pages or resources.
+
+The linked logo section pattern is composed of the following elements:
+
+| Element                           | Description                                                                               |
+| --------------------------------- | ----------------------------------------------------------------------------------------- |
+| title_text (**required**)         | `H2` title text.                                                                          |
+| Layout                            | Defaults to `full-width`, with additional options for `50-50`, and `25-75` layout splits. |
+| Links (**required**)              | An `Array<Object>` of individual image link properties.                                   |
+| Links[].href (**required**)       | The target link for the logo.                                                             |
+| Links[].text (**required**)       | The link text for the logo.                                                               |
+| Links[].label (**required**)      | The `aria-label` for the logo.                                                            |
+| Links[].image_html (**required**) | The logo image element.                                                                   |
+
+## Full width
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/default" class="js-example" data-lang="jinja">
+View example of the linked logo section full-width pattern
+</a></div>
+
+## 50/50
+
+This variant can be used for adding a header and the logo section in different columns. This should only be used when there’s a maximum of 6 logos to avoid occupying too much vertical space.
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/50-50" class="js-example" data-lang="jinja">
+View example of the linked logo section 50-50 pattern
+</a></div>
+
+## 25/75
+
+This variant can be used for adding a header and the logo section in different columns, but can accommodate up to 9 logos. Be aware that the heading only occupies 25% width here, so only very short titles would be appropriate here
+
+<div class="embedded-example"><a href="/docs/examples/patterns/linked-logo-section/25-75" class="js-example" data-lang="jinja">
+View example of the linked logo section 25-75 pattern
+</a></div>
+
+## Jinja Macro
+
+The `vf_linked_logo_section` Jinja macro can be used to generate a linked logo list pattern. The API for the macro is shown below.
+
+### Parameters
+
+<div style="overflow: auto;">
+  <table>
+    <thead>
+      <tr>
+        <th style="width: 220px;">Name</th>
+        <th style="width: 160px;">Required?</th>
+        <th style="width: 160px;">Type</th>
+        <th style="width: 160px;">Default</th>
+        <th style="width: 250px;">Description</th>
+      </tr>
+      <tbody>
+        <tr>
+          <td>
+            <code>title_text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            The text to be displayed as the heading (<code>h2</code>).
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>layout</code>
+          </td>
+          <td>
+            No
+          </td>
+          <td>
+            One of:<br>
+            <code>'50/50'</code>,<br>
+            <code>'25/75'</code>,<br>
+            <code>'full-width'</code>
+          </td>
+          <td>
+            <code>full-wdith</code>
+          </td>
+          <td>
+            The intended grid layout for the section.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            Array
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Array of image links.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].href</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Target link for the image.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].text</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Logo link text.
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].label</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            String
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            <code>aria-label</code> for the logo link. This attribute is added to the wrapping `a` tag under the hood and it is this label that screenreaders will read. Additional alt text added to the image element will be ignored by assistive techology and as such can be set to null.   
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <code>links[].image_html</code>
+          </td>
+          <td>
+            Yes
+          </td>
+          <td>
+            HTMLImageElement
+          </td>
+          <td>
+            N/A
+          </td>
+          <td>
+            Logo image element. This can be defined using raw HTML or using the <a href="https://github.com/canonical/canonicalwebteam.image-template/">Canonical image-template module</a>. Regardless of how this is initialized, it will need to include the <code>p-image-container__image</code> to comply with the <a href="/docs/patterns/images#highlighted-image">Highlighted image pattern</a> which wraps each link item under the hood. 
path: templates/docs/patterns/linked-logo-section/index.md
user: login: mtruj013
body: Agreed, I meant to add "class" here (hence the article before the class name) but left it out by mistake. Fixed!
created_at: 2025-04-04T08:04:56Z
author_association: CONTRIBUTOR

PR comments:
user: login: webteam-app
created_at: 2025-02-03T22:22:57Z
body: ### [<img src='https://assets.ubuntu.com/v1/6baef514-ubuntu-circle-of-friends-large.svg' height=32 width=32> Demo</img>](https://vanilla-framework-5464.demos.haus)
### [<img src='https://assets.ubuntu.com/v1/e512b0e2-jenkins.svg' height=32 width=32> Jenkins </img>](https://jenkins.canonical.com/webteam/job/start-demo/13594)
### [<img src='https://assets.ubuntu.com/v1/7144ec6d-logo-jaas-icon.svg' height=32 width=32> demos.haus </img>](https://demos.haus)

author_association: NONE
user: login: jmuzina
created_at: 2025-02-03T22:35:08Z
body: Built the bones of this one ahead of the spec being fully finished in order to do some research on how the API might work before I submit the engineering side of the spec.

Our usual method of building list-style HOCs (established [here](https://github.com/canonical/vanilla-framework/pull/5212)) is to create slots for each type of item content from `[1..n]` where `n` is the maximum number of elements allowed for the pattern, like so:

```html
{%- if slot == 'list_item_title_1' -%}
<h3 class="p-heading--5">Rich portfolio of products</h3>
{%- endif -%}

{%- if slot == 'list_item_description_1' -%}
<p>Resell the full range of Canonical’s portfolio of private and public
  cloud products: OpenStack, Kubernetes, IoT, support, security and
  compliance for Ubuntu.</p>
{%- endif -%}

{%- if slot == 'list_item_title_2' -%}
<h3 class="p-heading--5">Sales enablement</h3>
{%- endif -%}

{%- if slot == 'list_item_description_2' -%}
<p>Canonical can help train your field sales and presales teams and
  provide you with sales collateral and permission to use the Canonical
  and Ubuntu trademarks in your own materials.</p>
{%- endif -%}

{%- if slot == 'list_item_title_3' -%}
<h3 class="p-heading--5">Access to Canonical partner portal</h3>
{%- endif -%}

{%- if slot == 'list_item_description_3' -%}
<p>We host a partner portal with product and solutions collaterals, agreed
  pricing, incentives and a deal registration system.</p>
{%- endif -%}
<!-- and so on...-->
```

This does not trivially work for the linked logo section, because each item must be an `<a>` that contains other parts of the item as children. If the user passed in `list_item_n` as a wholesale slot, they wouldn't really be getting much value out of the HOC as they're constructing most of the markup themselves instead of the HOC handling it.

I.E., consider this to be the full HTML of one of the items:

```html
<a href="#" aria-label="Kubeflow">
  <div class="p-image-container--16-9 is-highlighted">
    <img class="p-image-container__image" src="https://assets.ubuntu.com/v1/cd89477e-kubeflow-logo-container-vert-fill.png" alt="Kubeflow logo" width="432" height="481">
  </div>
  <hr class="p-rule--muted">
  <p>Learn more ›</p>
</a>
```

Under the old approach, the consuming developer would need to do one of the following:
1. Create slots for the attributes of each link, i.e.:
```html
{% if slot == "link_1" %}
  href="#" aria-label="Kubeflow"
{% endif %}
```
2. Create a slot per attribute of each link:
```html
{% if slot == "link_1_href" %}
#
{% endif %}
{% if slot == "link_1_label" %}
Kubeflow
{% endif %}
```

Both of these feel a bit clumsy. So, I did some exploration of an alternate JSON-based approach to provide a bit more structure to the macro and improve the developer experience.

The resulting consumer code looks like this:

```html
{{ vf_linked_logo_section(
  title_text="PostgreSQL, security and support",
  links=[
    {
    "href": "#",
    "text": "Learn more &rsaquo;",
    "label": "Apache Spark",
    "image_html": image(url="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png",
      alt="",
      width="240",
      height="481",
      hi_def=True,
      loading="auto",
      attrs={"class": "p-image-container__image"}
    ) | safe
  }
  ],
) }}
```
author_association: MEMBER
user: login: bartaz
created_at: 2025-02-04T12:12:30Z
body: > ```
> "image_html": image(url="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png",
>       alt="",
>       width="240",
>       height="481",
>       hi_def=True,
>       loading="auto",
>       attrs={"class": "p-image-container__image"}
>     ) | safe
>   }
> ```

This makes me think if it would make sense to pass individual image attributes instead of `image_html` and pass them to `image` internally in the pattern. The downside would be the dependency on `image` template being available (and I'm not sure if we can enforce that on downstream projects), but it would have a benefit of additionally simplifying the API and removing redundant props.

 It could look like this, with nested image props:
```
{{ vf_linked_logo_section(
  title_text="PostgreSQL, security and support",
  links=[
    {
    "href": "#",
    "text": "Learn more &rsaquo;",
    "label": "Apache Spark",
    "image": {
      url="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png",
      alt="",
      width="240",
      height="481",
      }
  }
  ],
) }}
```

Or flattened: 

```
{{ vf_linked_logo_section(
  title_text="PostgreSQL, security and support",
  links=[
    {
    "href": "#",
    "text": "Learn more &rsaquo;",
    "label": "Apache Spark",
     "image_src"="https://assets.ubuntu.com/v1/855deda8-apache-spark-logo-container-vert-fill.png",
     "image_alt"="",
     "image_width"="240",
      "image_height"="481",
      }
  }
  ],
) }}
```
author_association: MEMBER
user: login: jmuzina
created_at: 2025-02-04T14:16:48Z
body: > This makes me think if it would make sense to pass individual image attributes instead of `image_html` and pass them to `image` internally in the pattern. The downside would be the dependency on `image` template being available (and I'm not sure if we can enforce that on downstream projects), but it would have a benefit of additionally simplifying the API and removing redundant props.

I thought of doing exactly this, but arrived at my current approach due to exactly what you said there: it would enforce the image template helper onto downstream projects. Passing in the `image_html` has the benefit of being tooling-agnostic, as any valid HTML passed in will work.

IDEs also do a fine job at recognizing this raw HTML and offering autocomplete and syntax highlighting, which I was worried about:

<img width="896" alt="Screenshot 2025-02-04 at 09 15 50" src="https://github.com/user-attachments/assets/022e9e3d-f2cd-436c-b66b-11da603a8326" />
<img width="896" alt="Screenshot 2025-02-04 at 09 15 54" src="https://github.com/user-attachments/assets/c1f4ee1f-d518-4f24-9269-1d2d0bb3b9ac" />



author_association: MEMBER
user: login: bartaz
created_at: 2025-02-04T14:38:08Z
body: 
> I thought of doing exactly this, but arrived at my current approach due to exactly what you said there: it would enforce the image template helper onto downstream projects. Passing in the `image_html` has the benefit of being tooling-agnostic, as any valid HTML passed in will work.

There is definitely a value in being tool-agnostic. And this is the main drawback I see and I don't know what consequences it would have to require the `image` from downstream projects.

There is probably less value in the field being free HTML. Because in such pre-defined pattern, do we want it to be free HTML? It seems we are expecting it to be an image, with a specific class name on top of it. This could benefit from being abstracted.

But there is obviously a drawback of relying on `image` template module.

There is a third option: to take image props directly and apply them in the pattern to `<img>` element (instead of going through `image` module), but that has a drawback of not using cloudinary and other built-in functionalities. 

author_association: MEMBER
user: login: jmuzina
created_at: 2025-02-05T15:24:36Z
body: Talked with @immortalcodes about this yesterday. He raised similar points as @bartaz but we arrived at raw HTML for the image as being the best approach, as sites generally uses the image template this must be compatible with the image template & cloudinary in order to create the least friction in their work. We should also avoid creating downstream dependencies on the image template. 

**The usage of the raw HTML should be adequately documented such that its usage (and expectation of `p-image-container__image` class) is clear.** 

In the future, when we are using React-based HOCs, this will become much simpler as we will be able to take advantage of more robust input handling and controls. This approach is a good medium-term solution. 
author_association: MEMBER
user: login: jmuzina
created_at: 2025-03-20T14:06:04Z
body: Sites is taking over this pattern's development from here.

A few things that should be worked on:
- Checking that responsiveness behaves properly
- Checking that the correct number of list items are allowed in each variant
- Possibly un-extracting the shared list items so they render properly in a docs page
- Building a docs page
author_association: MEMBER
user: login: mattea-turic
created_at: 2025-04-03T09:15:55Z
body: Looks great, thank you @jmuzina ! I honestly have no comments. +1ing :)


author_association: NONE
user: login: mtruj013
created_at: 2025-04-04T08:11:11Z
body: Thanks @jmuzina! All comments addressed 
author_association: CONTRIBUTOR
user: login: jmuzina
created_at: 2025-04-04T13:18:50Z
body: @advl Can you please approve this PR, I cannot approve it since I was the original author, and @mtruj013 can't approve it since she authored the most recent commit 😅 
author_association: MEMBER
user: login: jmuzina
created_at: 2025-04-04T13:33:19Z
body: [Approved](https://chat.canonical.com/canonical/pl/wc4kzz4b77fh9ym35rzsstepjr) by Gloria, per @mattea-turic 
author_association: MEMBER