Skip to content

Blog · Feb 21st, 2023 · 2 min read

Matt Stow avatar Matt Stow avatar

Matt Stow

Building layouts with placeholder components

An approach to rapidly building and evolving layouts as a project progresses and becomes more defined.

We’re in the early stages of building a complex application for a client. While we figure out how the underlying schema will work, we thought it would be a good idea to build the layout with placeholder components in place:

A responsive app layout using placeholder components

The placeholders give us a nice baseline to build from, and will provide obvious visual indication of progress to stakeholders as the real components replace them. We included image dimensions to help us make sure we use correct aspect ratios, and indicate to devs at a glance what sizes we’ll be needing.

Image component

The Image component simply takes width and height props and returns a placeholder image which automatically adds the dimensions. We used images instead of a styled HTML element to better understand how the layout might shift as they load.

function PlaceholderImage({ height, width, ...consumerProps }) {
  return (
    <Image
      {...consumerProps}
      alt=""
      src={`https://placehold.co/${width}x${height}.png`}
    />
  )
}

View this snippet as a Gist

Text component

We have a Text component that takes a number of characters and visually hides Lorem Ipsum up to that length and sets a repeating grey/white background to simulate text. Because it uses Plain Text under the hood, it responds and wraps sensibly.

const lipsum =
  'Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias quo voluptas fugit quidem nemo autem eos reprehenderit voluptatum nam. Error odio repellendus quisquam magni rerum hic facere laboriosam, aspernatur fugiat.'

function PlaceholderText({ characters, ...consumerProps }) {
  const string =
    characters <= lipsum.length
      ? lipsum.slice(0, characters)
      : lipsum
          .repeat(Math.ceil(characters / lipsum.length))
          .slice(0, characters)

  return (
    <span
      {...consumerProps}
      style={{
        backgroundImage:
          'repeating-linear-gradient(to bottom, #fff 0px, #fff 2px, #bbb 2px, #bbb 10px, #fff 10px, #fff 18px)',
        display: 'inline-block',
        fontSize: 12,
        lineHeight: 1,
      }}
    >
      <span style={{ visibility: 'hidden' }}>{string}</span>
    </span>
  )
}

View this snippet as a Gist

All in all, it’s been a handy way to create momentum on layout without adding a lot of technical debt.

Services discussed

Technology discussed

  • CSS
Matt Stow avatar Matt Stow avatar

Matt Stow

@stowball (opens in new window)

Senior UX Engineer at Thinkmill. Designs (digital, craft, board games). Writes (code, fiction, reviews). ❤️ a11y, Design Systems, alt rock, & Nintendo.

A photo of Jed Watson & Boris Bozic together A photo of Jed Watson & Boris Bozic together

We’d love to work with you

Have a chat with one of our co-founders, Jed or Boris, about how Thinkmill can support your organisation’s software ambitions.

Contact us