Back to gallery

A media component for images, video and embeds

More often than not, web pages contain images and embeds. What should these components do? These ones were designed at beam, a browser with a first-class note taking experience, and support for images and embeds.


Functional requirements

  • The component should support images and embeds
  • The component should display a loading state until the media has been loaded
  • The component should support passing predetermined dimensions to avoid layout shift
  • In the case of no predetermined dimensions, the component should load the media and properly resize
  • The component should support medias that are responsive, in either or both dimensions, and support medias that are not responsive
  • The component should be collapsible, except on small screens, where it should be expandable only if collapsed

Non-functional requirements

  • The component should be accessible to screen readers
  • The component should be accessible to keyboard users
  • The component should be accessible to mouse users
  • The component should be accessible to touch users
  • The component should honor prefers-reduced-motion
  • Animations should be interruptible

The loading state nobody sees

Loading states are the part of a media component you are least likely to get right, because you build them on a fast connection with a warm cache and they flash past before you can look at them. So this one holds. The component records how long the media actually took, and then keeps the loading state up for at least three seconds, which means the state you designed is a state you have watched.

It matters because the loading state is doing real work here. An embed has no dimensions until its provider answers, so if you let the layout settle first and correct it afterwards, everything below the media jumps. Passing known dimensions avoids that entirely, and where they are not known, the placeholder holds the space in the right proportion until the real thing arrives.

Collapsing to a real height

Collapsing is the other half. You cannot animate to auto, and picking a number means picking wrong for every embed that is not the one you tested with. A ResizeObserver watches the collapsed content and writes its measured height into a custom property, so the animation always runs to a height that exists, and it stays correct when the container is resized underneath it.

Video overview

Up next

A collapsible toolbar
-->
<--

Right before

A details (or disclosure) component