Theme
Design your own
On this page (4)
Component Skill — components/team-member/component-skill.md

Native basis

An <article> labelled by the name: a portrait (descriptive alt) with an optional location tag and a list of icon links over its bottom edge, then the name, the role and a short bio.

Web Platform APIs

<article>:has()object-fitaspect-ratioprefers-reduced-motion

Classes

.mk-team-member.mk-team-member-portrait.mk-team-member-photo.mk-team-member-tag.mk-team-member-links.mk-team-member-body.mk-team-member-name.mk-team-member-role.mk-team-member-bio

Data attributes

data-variant="horizontal", data-variant="compact".

§Team grid

Portrait cards: hover a card - or Tab into it - and the LinkedIn, GitHub, X and email links slide up over the photo (labelled per person; always shown on touch screens). A location tag sits in the corner.

§Horizontal

data-variant='horizontal': a card with the portrait beside the bio and the links always shown - for leadership and board pages.

§Compact

data-variant='compact': a round portrait with a ring, the name and the role on one row - for long team lists.

§CSS view file

/* -- Team Member (website · Company) --------------------------------------
   Presents one person with a portrait, role, and biography - a portrait card whose links slide in on hover, a profile beside its bio, or a compact row for long lists. */
@layer components {
  /* every box in the block measures border-box - the same on any page */
  :where(.mk-team-member, .mk-team-member *, .mk-team-member ::before, .mk-team-member ::after) {
    box-sizing: border-box;
  }
  .mk-team-member {
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
  }
  .mk-team-member-portrait {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    border-radius: var(--radius-xl);
    background: var(--muted);
    &::after {
      content: "";
      position: absolute;
      inset: 40% 0 0;
      z-index: 0;
      background: linear-gradient(transparent, oklch(0.12 0.02 260 / 0.65));
      opacity: 0;
      transition: opacity 300ms ease;
      pointer-events: none;
    }
  }
  .mk-team-member-photo {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    transition: scale 600ms cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .mk-team-member:is(:hover, :focus-within) .mk-team-member-photo {
    scale: 1.05;
  }
  .mk-team-member:is(:hover, :focus-within) .mk-team-member-portrait::after {
    opacity: 1;
  }
  .mk-team-member-tag {
    position: absolute;
    top: 0.75rem;
    left: 0.75rem;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.1875rem 0.5rem 0.1875rem 0.375rem;
    border-radius: 999px;
    background: color-mix(in oklch, var(--background) 82%, transparent);
    color: var(--foreground);
    font-size: 0.75rem;
    font-weight: 600;
    backdrop-filter: blur(8px);
    & svg {
      width: 0.75rem;
      height: 0.75rem;
    }
  }
  .mk-team-member-links {
    position: absolute;
    inset: auto 0.75rem 0.75rem;
    z-index: 1;
    display: flex;
    gap: 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
    opacity: 0;
    translate: 0 0.75rem;
    transition:
      opacity 250ms ease,
      translate 250ms ease;
    & a {
      display: grid;
      place-items: center;
      width: 2.25rem;
      height: 2.25rem;
      border-radius: 999px;
      background: oklch(1 0 0 / 0.92);
      color: oklch(0.2 0 0);
      box-shadow: var(--shadow-sm);
      transition:
        background-color 150ms ease,
        color 150ms ease;
    }
    & a:hover {
      background: var(--primary);
      color: var(--primary-foreground);
    }
    & a:focus-visible {
      outline: 2px solid #fff;
      outline-offset: 2px;
    }
    & svg {
      width: 1rem;
      height: 1rem;
    }
  }
  .mk-team-member:is(:hover, :focus-within) .mk-team-member-links {
    opacity: 1;
    translate: 0 0;
  }
  @media (hover: none) {
    .mk-team-member-links {
      opacity: 1;
      translate: 0 0;
    }
    .mk-team-member-portrait::after {
      opacity: 1;
    }
  }
  .mk-team-member-body {
    display: grid;
    gap: 0.125rem;
  }
  .mk-team-member-name {
    margin: 0;
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -0.01em;
  }
  .mk-team-member-role {
    margin: 0;
    color: var(--primary);
    font-size: 0.875rem;
    font-weight: 500;
  }
  .mk-team-member-bio {
    margin: 0.5rem 0 0;
    color: var(--muted-foreground);
    font-size: 0.9375rem;
    line-height: 1.6;
    text-wrap: pretty;
  }
  .mk-team-member[data-variant="horizontal"] {
    display: grid;
    grid-template-columns: minmax(8rem, 40%) minmax(0, 1fr);
    align-items: center;
    gap: 1.5rem;
    padding: 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    background: var(--card);
    color: var(--card-foreground);
    & .mk-team-member-photo {
      aspect-ratio: 1;
    }
    & .mk-team-member-links {
      opacity: 1;
      translate: 0 0;
      inset: auto 0.5rem 0.5rem;
      gap: 0.25rem;
    }
    & .mk-team-member-links a {
      width: 2rem;
      height: 2rem;
    }
    & .mk-team-member-portrait::after {
      opacity: 1;
    }
    & .mk-team-member-name {
      font-size: 1.25rem;
    }
  }
  .mk-team-member[data-variant="compact"] {
    flex-direction: row;
    align-items: center;
    gap: 0.875rem;
    & .mk-team-member-portrait {
      flex: none;
      width: 3rem;
      height: 3rem;
      border-radius: 50%;
      box-shadow:
        0 0 0 2px var(--background),
        0 0 0 3px var(--border);
    }
    & .mk-team-member-photo {
      height: 100%;
      aspect-ratio: 1;
    }
    & .mk-team-member-portrait::after,
    & .mk-team-member-tag,
    & .mk-team-member-links {
      display: none;
    }
    & .mk-team-member-name {
      font-size: 0.9375rem;
    }
    & .mk-team-member-role {
      color: var(--muted-foreground);
      font-weight: 400;
    }
  }
  /* -- Accessibility ------------------------------------------- */
  @media (prefers-reduced-motion: reduce) {
    .mk-team-member-photo,
    .mk-team-member-links,
    .mk-team-member-portrait::after {
      transition: none;
    }
    .mk-team-member:is(:hover, :focus-within) .mk-team-member-photo {
      scale: none;
    }
  }
  @media (forced-colors: active) {
    .mk-team-member-links a {
      border: 1px solid CanvasText;
    }
    .mk-team-member[data-variant="horizontal"] {
      border-color: CanvasText;
    }
  }
}

Comments, ideas or improvements? Edit this page's source on GitHub