Jan 2018

Conversational UI with Flexbox

Flexbox is my absolute favorite these days. I am using it all the time because it really makes my life easier. UI components and layouts that used to take a lot of floats and tweaking now are significantly easier to achieve with fewer lines of CSS. In this post I will show you how you can build a conversational UI with lots of flexbox, a tiny bit of JavaScript, and no floats. The end result will look like this:

Chat Flexbox Final Result

Identifying building blocks

What I like to do at the start of buidling a UI is to break the layout down into building blocks. Let's see what we have here:

Chat Flexbox Building Blocks

There is one large outer container, chat-container, that holds all the other elements. The rest of the elements are grouped into two sections - chat-log that will hold all messages, and chat-input-area that will contain an input field and a submit button. We will need to add a few more elements, but the structure will look something like this:

  <section class="chat-container">
    <div class="chat-log">
      <div class="chat-message">
        <p>Some text so we can see this container</p>
      </div>

      <div class="chat-message">
        <p>Some text so we can see this container</p>
      </div>
    </div>

    <form class="chat-input-area">
      <div class="chat-message">
        <p>Some text so we can see this container</p>
      </div>
    </form>
  </section>

Align to the bottom

This HTML structure allows us to stack the two inner sections one above the other by specifying the chat container as flexbox with flex-direction: column;.

  .chat-container {
    display: flex;
    flex-direction: column;
    height: 100vh;
  }

The chat container has 100vh height in order to stretch across all the viewport height, but its children won't take up all the available vertical space and they are now at the top of the chat container. In order to make them stick to the bottom of the chat container, we will add justify-content: flex-end; to the chat container styles.

Styling messages

The chat log consists of a list of chat messages. What we are missing in the current HTML structure is the avatar image, so let's add it:

  <div class="chat-log">
    <div class="chat-message">
      <span class="chat-message__avatar-frame">
        <img src="images/avatar-b.jpg" alt="avatar" class="chat-message__avatar">
      </span>
      <p class="chat-message__text">Hi!</p>
    </div>
  </div>

Each chat message is a flexbox with width: 100%;. We will leave the default flex direction of row, so the avatar and the text align next to each other. In order to align them vertically we will use align-items: center;.

  .chat-message {
    display: flex;
    align-items: center;
    width: 100%;
  }

Now, we also need a variation for the other user. The avatar image should be on the right side and the text should appear also to the right. All we need to add to our message variation class is:

  .chat-message--right {
    flex-direction: row-reverse;
  }

The image is on the right and the text is positioned left of it. We will still need to do further adjustments, like spacing between text and image etc, but we achieved what we needed without having to update our current markup or having to write alternative markup.

Scrolling contents up

We will be adding messages to the chat log container dynamically, whenever the user inputs something. We will need to scroll the contents up so the latest messages are visible at all times. Remember I said we will need a tiny bit of JavaScript? Here it comes:

  var chatLog = document.querySelectorAll('.chat-container__chat-log');
  chatLog[0].scrollTop = chatLog[0].scrollHeight;

What we do here is we make sure that the scroll distance of the chat log becomes equal to its height. This way the container will always be scrolled to its bottom, so newest contents will be visible right above the input field.

Animation

We can add a nice fly in animation to each message that was just added to the chat log. We will add this animation to the .chat-message__text styles. The animation will happen once when the element is first added to the DOM.

  @keyframes fly-in {
    0% {
      transform: scale(0.85) translateY(10%);
      opacity: 0;
    }
    100% {
      transform: scale(1) translateY(0);
      opacity: 1;
    }
  }

Conclusion

I hope this article will inspire you to use flexbox more often now. Flexbox is really powerful and can help you create interesting layouts with CSS that are clearer and more maintainable.

If you want to dig more into flexbox, MDN Flexbox and A Complete Guide to Flexbox are a great place to start.

I have integrated this conversational UI demo with Dialog Flow, the former api dot ai. It helps you build your own chatbot agent that receives user inputs and replies in a meaningful way depending on the training it has received. It is free of charge and it is absolutely worth exploring.