<article class="mediaObject mediaObject--cta ">
    <div class="mediaObject__body">
        <header class="mediaObject__header">
            <h2 class="mediaObject__title">
                <a href="#" class="mediaObject__link" aria-describedby="media-heading">Media Heading</a>
            </h2>
            <span class="mediaObject__postDate u-step--2">December 2, 2022</span>
        </header>
        <p class="mediaObject__excerpt">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore</p>
        <span class="mediaObject__pseudoLink" id="media-heading">Read more<span class="appendedIcon">&zwj;<i class="fas fa-angle-right"></i></span></span>
    </div>
    <img srcset="https://placehold.co/269x179,
          https://placehold.co/538x358 2x" src="https://placehold.co/538x358" class="mediaObject__img" alt="Generic placeholder image" />
</article>

<link media="all" rel="stylesheet" href="/media-object/media-object.css" />
<script src="/media-object/media-object.js"></script>
<article class="mediaObject {% if cta %}mediaObject--cta{% endif %} {{ containerClass }}">
  <div class="mediaObject__body">
    <header class="mediaObject__header">
      {% if cta %}
        <h2 class="mediaObject__title">
          <a href="{{ url }}" class="mediaObject__link" aria-describedby="{{ slug }}">{{ title }}</a>
        </h2>
      {% else %}
        <span class="mediaObject__title">{{ title }}</span>
      {% endif %}
      <span class="mediaObject__postDate u-step--2">{{ postDate }}</span>
    </header>
    <p class="mediaObject__excerpt">{{ excerpt }}</p>
    {% if cta and readmore != false %}
      <span class="mediaObject__pseudoLink" id="{{ slug }}">{% render "@icon--appended" with {text: "Read more"} %}</span>
    {% endif %}
  </div>
  <img
      srcset="https://placehold.co/269x179,
          https://placehold.co/538x358 2x"
      src="https://placehold.co/538x358"
      class="mediaObject__img"
      alt="{{ imgAlt }}"
  />
</article>

{% import "_macros.twig" as h %}
{{ h.componentAssets('media-object') }}
{
  "title": "Media Heading",
  "postDate": "December 2, 2022",
  "imgAlt": "Generic placeholder image",
  "excerpt": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore",
  "cta": true,
  "url": "#",
  "slug": "media-heading"
}
  • Content:
    @use "../_layout/mixins";
    
    .mediaObject {
      display: flex;
      align-items: flex-start;
      flex-wrap: wrap;
      gap: 1em;
    }
    .mediaObject--vertical {
      --mediaObjectImgMaxWidth: 100%;
      flex-direction: column;
      flex-wrap: nowrap;
    
      .mediaObject__img {
        width: 100%;
      }
    }
    .mediaObject__img {
      order: -1;
      flex: 1;
      width: 25%;
      max-width: var(--mediaObjectImgMaxWidth, 325px);
      min-width: var(--mediaObjectImgMinWidth, 230px);
      height: auto;
    }
    .mediaObject__body {
      flex: 1 1 50%;
    }
    .mediaObject__header {
      display: flex;
      flex-direction: column;
    }
    .mediaObject__postDate {
      order: -1;
      margin: 0;
    }
    .mediaObject__title {
      font-size: var(--step-3);
      font-weight: var(--bold-weight);
      line-height: 1.2;
      display: block;
      margin-block: 0;
    }
    .mediaObject__link {
      background-image: none;
      --color: var(--blue);
      --hoverColor: var(--blue--dark);
      text-decoration: underline;
      text-decoration-thickness: 3px;
    
      &:hover, &:focus {
        --color: var(--hoverColor);
      }
    }
    .mediaObject__header + p,
    .mediaObject__excerpt {
      margin-block: 0.5em;
    }
    .mediaObject--selectableContent {
      .mediaObject__postDate,
      .mediaObject__header ~ p,
      .mediaObject__excerpt {
        position: relative;
      }
    }
    .mediaObject__pseudoLink {
      @include mixins.link();
      @include mixins.blockLink();
      display: inline-block;
    }
    
    .mediaObject--cta {
      position: relative;
    
      .mediaObject__link {
        transition: color 0.2s ease-out;
        &:after {
          content: "";
          @include mixins.fillParent();
        }
      }
      .mediaObject__pseudoLink {
        transition: color 0.2s ease-out;
      }
    
      // Change the link color but not if 'selectable content' is being hovered
      // see https://stackoverflow.com/a/73798067/1231466
      &:hover, &:focus {
        &:not(
          :has(
            :is(
              .mediaObject__postDate,
              .mediaObject__header ~ p,
              .mediaObject__excerpt
            ):hover
          )
        ) {
          .mediaObject__link {
            --color: var(--hoverColor);
          }
    
          .mediaObject__pseudoLink {
            --color: var(--hoverColor);
          }
        }
      }
    }
    
  • URL: /components/raw/media-object/media-object.scss
  • Filesystem Path: src/components/media-object/media-object.scss
  • Size: 2 KB

The media object helps build complex and repetitive components where some media is positioned alongside content that doesn’t wrap around said media. For example, a list of blog posts or publications.

When using the .mediaObject--cta modifier, the ‘Read more’ pseudo link can be optional as the title acts as a clear actionable link.

When using media objects as cards, for instance as a list of blog posts, make sure to use the correct semantic markup, including <article>, <header> and the correct heading:

<article class="mediaObject mediaObject--cta">
  <div class="mediaObject__body">
    <header class="mediaObject__header">
      <span class="mediaObject__postDate u-step--2">December 2, 2022</span>
      <h3 class="mediaObject__title">
        <a href="#" class="mediaObject__link" aria-describedby="unique-id"
          >A media object</a
        >
      </h3>
    </header>
    <p class="mediaObject__excerpt">Lorem lipsum...</p>
    <span class="mediaObject__pseudoLink" id="unique-id">Read more</span>
  </div>
  <img src="#" class="mediaObject__img" alt="A generic placeholder image" />
</article>