Empties are unstyled Refills components and patterns built with Bourbon and Neat.

Managed by thoughtbot, source at GitHub

<ul class="accordion">
  <li>
    <a href="javascript:void(0)" class="js-accordion-trigger">Accordion Item</a>
    <ul class="submenu">
      <li>
        <a href="javascript:void(0)">Sub Item 1</a>
      </li>
      <li>
        <a href="javascript:void(0)">Sub Item 2</a>
      </li>
    </ul>
  </li>
  <li>
    <a href="javascript:void(0)" class="js-accordion-trigger">Another Item</a>
    <ul class="submenu">
      <li>
        <a href="javascript:void(0)">Sub Item 1</a>
      </li>
      <li>
        <a href="javascript:void(0)">Sub Item 2</a>
      </li>
    </ul>
  </li>
</ul>
.accordion {  
  > li > a {
    font-weight: normal;
  }

  ul.submenu {
    display: none;
  }

  .is-expanded {
    > a {
      color: red;
    }

    display: block;
  }
}
$('.js-accordion-trigger').bind('click', function(e){
  jQuery(this).parent().find('.submenu').slideToggle('fast');  // apply the toggle to the ul
  jQuery(this).parent().toggleClass('is-expanded');
  e.preventDefault();
});
$('.js-accordion-trigger').bind 'click', (e) ->
  jQuery(this).parent().find('.submenu').slideToggle 'fast'
  jQuery(this).parent().toggleClass 'is-expanded'
  e.preventDefault()
  return
Accordion / Tabs
  • Tab Item

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras tincidunt pellentesque lorem.Nullam imperdiet sapien id purus pretium id aliquam mi ullamcorper.

  • Another Tab

    Ut laoreet augue et neque pretium non sagittis nibh pulvinar. Etiam ornare tincidunt orci quis ultrices. Pellentesque ac sapien ac purus gravida ullamcorper. Duis rhoncus sodales lacus, vitae adipiscing tellus pharetra sed. Praesent bibendum lacus quis metus condimentum ac accumsan orci vulputate.

  • Third

    Donec mattis mauris gravida metus laoreet non rutrum sem viverra. Aenean nibh libero, viverra vel vestibulum in, porttitor ut sapien. Phasellus tempor lorem id justo ornare tincidunt. Nulla faucibus, purus eu placerat fermentum, velit mi iaculis nunc, bibendum tincidunt ipsum justo eu mauris. Nulla facilisi. Vestibulum vel lectus ac purus tempus suscipit nec sit amet eros. Nullam fringilla, enim eu lobortis dapibus, quam magna tincidunt nibh, sit amet imperdiet dolor justo congue turpis.

  • Last Item

    Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus dui urna.

<ul class="accordion-tabs">
  <li class="tab-header-and-content">
    <a href="javascript:void(0)" class="is-active tab-link">Tab Item</a>
    <div class="tab-content">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras tincidunt pellentesque lorem.Nullam imperdiet sapien id purus pretium id aliquam mi ullamcorper.</p>
    </div>
  </li>
  <li class="tab-header-and-content">
    <a href="javascript:void(0)" class="tab-link">Another Tab</a>
    <div class="tab-content">
      <p>Ut laoreet augue et neque pretium non sagittis nibh pulvinar. Etiam ornare tincidunt orci quis ultrices. Pellentesque ac sapien ac purus gravida ullamcorper. Duis rhoncus sodales lacus, vitae adipiscing tellus pharetra sed. Praesent bibendum lacus quis metus condimentum ac accumsan orci vulputate.</p>
    </div>
  </li>
  <li class="tab-header-and-content">
    <a href="javascript:void(0)" class="tab-link">Third</a>
    <div class="tab-content">
      <p>Donec mattis mauris gravida metus laoreet non rutrum sem viverra. Aenean nibh libero, viverra vel vestibulum in, porttitor ut sapien. Phasellus tempor lorem id justo ornare tincidunt. Nulla faucibus, purus eu placerat fermentum, velit mi iaculis nunc, bibendum tincidunt ipsum justo eu mauris. Nulla facilisi. Vestibulum vel lectus ac purus tempus suscipit nec sit amet eros. Nullam fringilla, enim eu lobortis dapibus, quam magna tincidunt nibh, sit amet imperdiet dolor justo congue turpis.</p>
    </div>
  </li>
  <li class="tab-header-and-content">
    <a href="javascript:void(0)" class="tab-link">Last Item</a>
    <div class="tab-content">
      <p>Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus dui urna.</p>
    </div>
  </li>
</ul>
.accordion-tabs {
  $large-screen: 50em !default;

  @include clearfix;
  padding: 0;

  .tab-header-and-content {
    list-style: none;

    @include media($large-screen) {
      display: inline;
    }
  }

  .tab-link {
    display: block;
    padding-right: 1em;

    @include media($large-screen) {
      display: inline-block;
    }
  }

  .is-active {
    color: #ff0000;
  }

  .tab-content {
    display: none;
    width: 100%;

    @include media($large-screen) {
      float: left;
    }
  }
}
$(document).ready(function () {
  $('.accordion-tabs').each(function(index) {
    $(this).children('li').first().children('a').addClass('is-active').next().addClass('is-open').show();
  });
  $('.accordion-tabs').on('click', 'li > a.tab-link', function(event) {
    if (!$(this).hasClass('is-active')) {
      event.preventDefault();
      var accordionTabs = $(this).closest('.accordion-tabs');
      accordionTabs.find('.is-open').removeClass('is-open').hide();

      $(this).next().toggleClass('is-open').toggle();
      accordionTabs.find('.is-active').removeClass('is-active');
      $(this).addClass('is-active');
    } else {
      event.preventDefault();
    }
  });
});
$(document).ready ->
  $('.accordion-tabs').each ->
    $(this).children('li').first().children('a').addClass('is-active').next().addClass('is-open').show()
    return
  $('.accordion-tabs').on 'click', 'li > a.tab-link', (event) ->
    if !$(this).hasClass('is-active')
      event.preventDefault()
      accordionTabs = $(this).closest('.accordion-tabs')
      accordionTabs.find('.is-open').removeClass('is-open').hide()
      $(this).next().toggleClass('is-open').toggle()
      accordionTabs.find('.is-active').removeClass 'is-active'
      $(this).addClass 'is-active'
    else
      event.preventDefault()
    return
  return
Button Group
<div class="button-group">
  <label>
    <input type="radio" name="button-group" value="item" checked>
    <span class="button-group-item">Item</span>
  </label>
  <label>
    <input type="radio" name="button-group" value="other-item">
    <span class="button-group-item">Other But Longer Item</span>
  </label>
  <label>
    <input type="radio" name="button-group" value="other-item">
    <span class="button-group-item">Third</span>
  </label>
  <label>
    <input type="radio" name="button-group" value="third">
    <span class="button-group-item">Last Item</span>
  </label>
</div>
.button-group {  
  $large-screen: 50em !default;

  input {
    display: none;
  }

  label {
    font-weight: normal;

    @include media($large-screen) {
      float: left;
      padding: 0 0.5em;
    }
  }

  .button-group-item {
    cursor: pointer;
    display: inline-block;
    width: 100%;

    @include media($large-screen) {
      width: auto;
    }
  }

  input:checked + .button-group-item {
    color: #ff0000;
  }
}
Button with icon
<button class="button-icon">Button with icon</button>
.button-icon {
  $icon-size: 1.6em;
  background-color: whitesmoke;
  padding: 1em;
  width: 100%;

  &:before {
    @include size($icon-size);
    background-image: url(https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/placeholder_small.png);
    background-repeat: no-repeat;
    background-size: $icon-size;
    content: "";
    display: inline-block;
    margin-right: 1em;
    vertical-align: middle;
  }
}
Cards

First Card

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga, officiis sunt neque facilis culpa molestiae necessitatibus delectus veniam provident.

Another Card

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga, officiis sunt neque facilis culpa molestiae necessitatibus delectus veniam provident.

The Last Card

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

<div class="cards">
  <div class="card">
    <div class="card-image"></div>
    <div class="card-header">
      <h4>First Card</h4>
    </div>
    <div class="card-copy">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga, officiis sunt neque facilis culpa molestiae necessitatibus delectus veniam provident.</p>
    </div>
  </div>

  <div class="card">
    <div class="card-image"></div>
    <div class="card-header">
      <h4>Another Card</h4>
    </div>
    <div class="card-copy">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga, officiis sunt neque facilis culpa molestiae necessitatibus delectus veniam provident.</p>
    </div>
  </div>

  <div class="card">
    <div class="card-image"></div>
    <div class="card-header">
      <h4>The Last Card</h4>
    </div>
    <div class="card-copy">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
    </div>
  </div>
</div>
.cards {
  @include display(flex);
  @include flex-wrap(wrap);
  @include justify-content(space-between);

  .card {
    @include flex-basis(20em);
    @include flex-grow(1);
    margin: 0 1em;
  }
  
  .card-image {
    height: 15em;
    background: whitesmoke;
    overflow: hidden;

    img {
      width: 100%;
    }
  }
}
Comments

First Comment Title or Author

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Optio, aspernatur, quia modi minima debitis tempora ducimus quam vero impedit alias earum nemo error tenetur sed.

Another One

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Optio, aspernatur, quia modi minima debitis tempora ducimus quam vero impedit alias earum nemo error tenetur sed.

<div class="comment">
  <div class="comment-image">
    <img src="https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/placeholder.png">
  </div>
  <div class="comment-content">
    <h4>First Comment Title or Author</h4>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Optio, aspernatur, quia modi minima debitis tempora ducimus quam vero impedit alias earum nemo error tenetur sed.</p>
  </div>
</div>

<div class="comment">
  <div class="comment-image">
    <img src="https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/placeholder.png">
  </div>
  <div class="comment-content">
    <h4>Another One</h4>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Optio, aspernatur, quia modi minima debitis tempora ducimus quam vero impedit alias earum nemo error tenetur sed.</p>
  </div>
</div>
.comment {
  display: table;
  width: 100%;

  .comment-image,
  .comment-content {
    display: table-cell;
    vertical-align: top;
  }

  h4 {
    margin-top: 0;
  }

  .comment-image {
    padding-right: $gutter;

    img {
      height: 3em;
      max-width: none;
    }

    .comment-reverse-order & {
      padding-left: 10px;
      padding-right: 0;
    }
  }

  .comment-content {
    width: 100%;
  }
}
Expander
Expandable section

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio mollitia fugiat facilis enim accusamus quisquam aut, repellendus incidunt quod optio facere labore illo numquam ipsum beatae vero debitis, fugit excepturi.

<div class="expander">
  <a href="javascript:void(0)" class="expander-trigger expander-hidden">Expandable section</a>
  <div class="expander-content">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio mollitia fugiat facilis enim accusamus quisquam aut, repellendus incidunt quod optio facere labore illo numquam ipsum beatae vero debitis, fugit excepturi.</p>
  </div>
</div>
.expander {
  width: 25em;

  .expander-trigger {
    display: block;

    &:before {
      content: "\25BC";
      margin-right: 0.5em;
    }
  }

  .expander-hidden {
    &:before {
      content: "\25BA";
    }
  }

  .expander-hidden + .expander-content {
    display: none;
  }
}
$(document).ready(function() {
  $('.expander-trigger').click(function(){
    $(this).toggleClass("expander-hidden");
  });
});
$(document).ready ->
  expanderTrigger = document.getElementById('js-expander-trigger')
  expanderContent = document.getElementById('js-expander-content')
  $('#js-expander-trigger').click ->
    $(this).toggleClass 'expander-hidden'
    return
  return
Grid
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
<div class="grid">
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
  <div class="grid-box-wrap"><div class="grid-box">Content</div></div>
</div>
.grid {
  $grid-gutter: 0.1rem;

  display: flex;
  flex-flow: row wrap;
  margin: 0 - $grid-gutter;

  .grid-box-wrap {
    flex-basis: 20rem;
    flex-grow: 1;
    flex-shrink: 0;
    overflow: hidden;
    padding: 0 $grid-gutter ($grid-gutter * 2);
  }

  .grid-box {
    background: whitesmoke;
    text-align: center;
  }
}

// Based on code by http://codepen.io/heydon/
Hero

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magni modi doloremque excepturi laudantium maxime explicabo cumque deleniti voluptate deserunt.

<div class="hero">
  <div class="hero-content">
    <img src="https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/placeholder.png" alt="Logo Image" class="hero-logo">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magni modi doloremque excepturi laudantium maxime explicabo cumque deleniti voluptate deserunt.</p>
  </div>
</div>
.hero {
  $large-screen: 50em !default;
  align-items: center;
  background: image_url("https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/background-image.png");
  background-position: right;
  background-size: none;
  display: flex;
  justify-content: center;
  min-height: 25em;
  padding: 2em;

  @include media($large-screen) {
    background-size: cover;
    background-position: left;
    justify-content: flex-end;
  }

  .hero-content {
    max-width: 20em;
    text-align: center;

    @include media($large-screen) {
      text-align: left;
    }
  }

  .hero-logo {
    margin: auto;
  }
}
Login
<div class="login">
  <img src="https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/placeholder.png" alt="Logo Image" class="login-logo">
  <label for="">Email</label>
  <input type="text">
  <label for="">Password</label>
  <a href="" class="forgot-password">Forgot password?</a>
  <input type="text">
  <button type="submit" class="login-button">Log In</button>
  <label class="remember-me">
    <input type="checkbox">
    Remember me
  </label>
</div>
.login {
  .login-logo {
    display: block;
    margin: auto;
    height: 3em;
  }

  label {
    float: left;
  }

  input[type="text"] {
    width: 100%;
  }

  .forgot-password {
    float: right;
  }

  .login-button {
    float: left;
  }

  .remember-me {
    float: right;
  }

  input[type="checkbox"] {
    display: inline;
  }
}

<div class="login-stacked">
  <img src="https://raw.githubusercontent.com/thoughtbot/empties/master/source/images/placeholder.png" alt="Logo Image" class="login-logo">
  <input type="text" placeholder="email">
  <input type="text" placeholder="password">
  <button type="submit" class="login-button">Log In</button>
  <a href="" class="forgot-password">Forgot password?</a>
  <label class="remember-me">
    <input type="checkbox">
    Remember me
  </label>
</div>
.login-stacked {
  .login-logo {
    display: block;
    margin: 0 auto 2em;
    height: 3em;
  }

  label {
    float: left;
  }

  input[type="text"] {
    width: 100%;
  }

  .forgot-password {
    float: right;
  }

  .login-button {
    width: 100%;
  }

  .remember-me {
    float: left;
  }

  input[type="checkbox"] {
    display: inline;
  }
}

<li class="nav-link hover-menu">
  <a href="javascript:void(0)">More</a>
  <ul class="submenu">
    <li class="hover-menu">
      <a href="javascript:void(0)" class="hover-menu-item">Item with submenu</a>
      <ul class="submenu">
        <li><a href="javascript:void(0)">Submenu Item</a></li>
        <li><a href="javascript:void(0)">Another Item</a></li>
      </ul>
    </li>
  </ul>
</li>
.hover-menu {
  $large-screen: 50em !default;
  $submenu-width: 12em;

  overflow: visible;
  padding-right: 0;

  @include media($large-screen) {
    position: relative;
  }

  .hover-menu-item {
    left: 0;
    position: relative;

    &::after {
      content: "›";
      padding-left: 0.5em;
    }
  }

  .submenu {
    display: none;
    margin: 0;
    padding-left: 0;

    @include media($large-screen) {
      left: 0;
      position: absolute;
    }
  }

  .submenu li {
    display: block;
    padding-right: 0;
  }

  .submenu li a {
    display: inline-block;
    text-align: right;
    width: 100%;

    @include media($large-screen) {
      text-align: left;
      width: $submenu-width;
    }
  }

  .submenu .submenu {
    @include media($large-screen) {
      left: $submenu-width;
      top: 0;
    }
  }

  &:focus > .submenu,
  &:hover > .submenu {
    display: block;
  }
}