Messages

Messages component will help you with visualisation of comments and messaging system in your app.

Messages Layout

<div class="page">
  <div class="page-content messages-content">
    <div class="messages">
      <!-- Date stamp -->
      <div class="messages-title"><b>Sunday, Feb 9</b> 12:58</div>

      <!-- Sent message (by default - green and on right side) -->
      <div class="message message-sent">
        <div class="message-content">
          <!-- Bubble with text -->
          <div class="message-bubble">
            <div class="message-text">Hi, Kate</div>
          </div>
        </div>
      </div>

      <!-- Another sent message -->
      <div class="message message-sent">
        <div class="message-content">
          <div class="message-bubble">
            <div class="message-text">How are you?</div>
          </div>
        </div>
      </div>

      <!-- Received message (by default - grey on left side) -->
      <div class="message message-received">
        <!-- Sender avatar -->
        <div class="message-avatar" style="background-image:url(path/to/avatar.jpg)"></div>
        <div class="message-content">
          <!-- Sender name -->
          <div class="message-name">Blue Ninja</div>
          <!-- Bubble with text -->
          <div class="message-bubble">
            <div class="message-text">Hi there, I am also fine, thanks! And how are you?</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Messages page layout:

  • messages-content - required additional class for messages wrapper. Should be added to page-content

  • messages - required additional wrapper for messages bubbles. Required element.

  • messages-title - messages title

  • message - single message

Single Message Layout

Here is a full single message layout:

<div class="message">
  <div class="message-avatar" style="background-image:url(path/to/avatar)"></div>
  <div class="message-content">
    <div class="message-name">John Doe</div>
    <div class="message-header">Message header</div>
    <div class="message-bubble">
      <div class="message-text-header">Text header</div>
      <div class="message-image">
        <img src="path/to/image" />
      </div>
      <div class="message-text">Hello world!</div>
      <div class="message-text-footer">Text footer</div>
    </div>
    <div class="message-footer">Message footer</div>
  </div>
</div>
  • message-avatar - sender avatar, optional

  • message-name - sender name, optional

  • message-header - single message header, optional

  • message-text-header - text header inside of bubble, optional

  • message-image - message image, optional

  • message-text - message text, optional

  • message-text-footer - text footer inside of bubble, optional

  • message-footer - footer text after bubble, optional

Additional classes for single message container

  • message-sent - additional class for single message which indicates that this message was sent by user. It stays on right side with green background color.

  • message-received - additional class for single message which indicates that this message was received by user. It stays on left side with grey background color.

  • message-tail - additional class for single message (received or sent) to add bubble "tail"

  • message-same-name - additional class for indicating that message has same sender name as previous message

  • message-same-avatar - additional class for indicating that message has same avatar as previous message

  • message-same-header - additional class for indicating that message has same message-header as previous message

  • message-same-footer - additional class for indicating that message has same message-footer as previous message

  • message-last - additional class for single message (received or sent) to indicate last received or last sent message in current conversation by one sender

  • message-first - additional class for single message (received or sent) to indicate first received or first sent message in current conversation by one sender

Messages App Methods

Now, when we have Messages' HTML, we need to initialize it. We need to use related App's method:

app.messages.create(parameters)Initialize Messages with parameters
  • parameters - object - object with Messages parameters
  • Method returns initialized Messages instance
app.messages.destroy(el)Destroy Messages instance
  • el - HTMLElement or string (with CSS Selector) or object. Messages element or Messages instance to destroy.
app.messages.get(el)Get Messages instance by HTML element
  • el - HTMLElement or string (with CSS Selector). Messages element.
  • Method returns Messages's instance

Messages Parameters

Let's look on list of all available parameters:

ParameterTypeDefaultDescription
autoLayoutbooleantrueEnable Auto Layout to add all required additional classes automatically based on passed conditions
newMessagesFirstbooleanfalseEnable if you want to use new messages on top, instead of having them on bottom
scrollMessagesbooleantrueEnable/disable messages autoscrolling when adding new message
scrollMessagesOnEdgebooleantrueIf enabled then messages autoscrolling will happen only when user is on top/bottom of the messages view
messagesarrayArray with initial messages. Each message in array should be presented as an object with single message parameters
onobject

Object with events handlers. For example:

var messages = app.messages.create({
  el: '.messages',
  on: {
    change: function () {
      console.log('Textarea value changed')
    }
  }
})
renderMessagefunction(message)Function to render single message. Must return full message HTML string
Autolayout Conditions
firstMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-first class will be added to message
lastMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-last class will be added to message
tailMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-tail class will be added to message
sameNameMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-same-name class will be added to message
sameHeaderMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-same-header class will be added to message
sameFooterMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-same-footer class will be added to message
sameAvatarMessageRulefunction(message, previousMessage, nextMessage)Function that must return boolean true or false based on required condition depending on previous and next messages. In case of match then message-same-avatar class will be added to message
customClassMessageRulefunction(message, previousMessage, nextMessage)Function that must return additional message classes as string, based on required condition depending on previous and next messages.

Single Message Parameters

Let's look on single message parameters object that we should use when we pass messages array:

ParameterTypeDefaultDescription
textstringMessage text
headerstringSingle message header
footerstringSingle message footer
namestringSender name
avatarstringSender avatar URL string
typestringsentMessage type - sent or received
textHeaderstringMessage text header
textFooterstringMessage text footer
imagestringMessage image HTML string, e.g. <img src="path/to/image" />. Can be used instead of imageSrc parameter
imageSrcstringMessage image URL string. Can be used instead of image parameter
isTitlebooleanDefines whether it should be rendered as a message or as a messages title
cssClassstringAdditional CSS class to set on message HTML element
attrsobjectObject with additional HTML attributes to be set on message HTML element. For example to set extra data attributes it should look like:
var message = {
  text: 'Hello!',
  attrs: {
    'data-id': 1,
    'data-author-id': 150
  }
}

Messages Methods & Properties

So to create Messages we have to call:

var messages = app.messages.create({ /* parameters */ })

After we initialize Messages we have its initialized instance in variable (like messages variable in example above) with helpful methods and properties:

Properties
messages.paramsObject with passed initialization parameters
messages.elMessages container HTML element (<div class="messages">)
messages.$elDom7 element with messages HTML element
messages.messagesArray with messages
Methods
messages.showTyping(message)Show typing message indicator
messages.hideTyping()Hide typing message indicator
messages.addMessage(message, method, animate);

Add new message to the end or to the beginning depending on method parameter

  • message - object - parameters of message to add. Required.
  • method - string - (append or prepend) dictates to add new message in the end or in the beginning of messages container. Optional, if not specified, then it will add message depending on newMessagesFirst parameter
  • animate - boolean - (by default true) You may pass here false and message will be added immediately without any transiton and scrolling animation. Optional.
  • Method returns Messages instance
messages.addMessages(messages, method, animate);Add multiple messages per once.
  • messages - array with messages to add. Each message in array should be presented as an object with message parameters Required.
  • Method returns Messages instance
messages.removeMessage(message);Remove message
  • message - HTMLElement or string (with CSS Selector) or number (with index number of message from messages array) of message to remove
  • Method returns Messages instance
messages.removeMessages(messages);Remove multiple messages
  • messages - array with messages to remove
  • Method returns Messages instance
messages.scroll(duration, position);Scroll messages to top/bottom depending on newMessagesFirst parameter
  • duration - number scroll duration in ms
  • position - number scroll position in px
messages.renderMessages()Render messages HTML depending on messages array
messages.layout();Force messages auto layout
messages.clear();Clear/remove all the messages
messages.destroy();Destroy messages instance

Messages Events

Messages will fire the following DOM events on messages element and events on app and messages instance:

DOM Events

EventTargetDescription
messages:beforedestroyMessages Element<div class="messages">Event will be triggered right before Messages instance will be destroyed

App and Messages Instance Events

Messages instance emits events on both self instance and app instance. App instance events has same names prefixed with messages.

EventTargetArgumentsDescription
beforeDestroymessages(messages)Event will be triggered right before Messages instance will be destroyed
messagesBeforeDestroyapp

Messages Auto Initialization

If you don't need to use Messages API and your Messages is inside of the page and presented in DOM on moment of page initialization then it can be auto initialized with just adding additional messages-init class to messages element, and all required parameters can be passed using data- attributes:

<div class="messages messages-init" data-new-messages-first="true">
  ...
</div>

Parameters that used in camelCase, for example newMessagesFirst, in data- attributes should be used in kebab-case as data-new-messages-first

CSS Variables

Below is the list of related CSS variables (CSS custom properties).

Note that commented variables are not specified by default and their values is what they fallback to in this case.

:root {
  --f7-message-text-header-text-color: inherit;
  --f7-message-text-header-opacity: 0.65;
  --f7-message-text-header-font-size: 12px;
  --f7-message-text-footer-text-color: inherit;
  --f7-message-text-footer-opacity: 0.65;
  --f7-message-text-footer-font-size: 12px;
  --f7-message-bubble-line-height: 1.2;
  --f7-message-header-font-size: 12px;
  --f7-message-footer-font-size: 11px;
  --f7-message-name-font-size: 12px;
  --f7-message-name-font-weight: inherit;
  --f7-message-avatar-border-radius: 50%;
  --f7-messages-title-font-weight: inherit;
  /*
  --f7-message-sent-bg-color: var(--f7-theme-color);
  */
  --f7-message-sent-text-color: #fff;
  --f7-messages-content-bg-color: #fff;
  --f7-message-typing-indicator-bg-color: #000;
  --f7-message-received-bg-color: #e5e5ea;
  --f7-message-received-text-color: #000;
}
:root .dark,
:root.dark {
  --f7-messages-title-text-color: rgba(255, 255, 255, 0.54);
  --f7-message-header-text-color: rgba(255, 255, 255, 0.54);
  --f7-message-name-text-color: rgba(255, 255, 255, 0.54);
  --f7-message-footer-text-color: rgba(255, 255, 255, 0.54);
  --f7-messages-content-bg-color: transparent;
  --f7-message-received-bg-color: #252525;
  --f7-message-received-text-color: #fff;
  --f7-message-typing-indicator-bg-color: #fff;
}
.ios {
  --f7-messages-title-text-color: rgba(0, 0, 0, 0.45);
  --f7-messages-title-font-size: 11px;
  --f7-message-header-text-color: rgba(0, 0, 0, 0.45);
  --f7-message-footer-text-color: rgba(0, 0, 0, 0.45);
  --f7-message-name-text-color: rgba(0, 0, 0, 0.45);
  --f7-message-avatar-size: 29px;
  --f7-message-margin: 10px;
  --f7-message-bubble-min-height: 32px;
  --f7-message-bubble-font-size: 17px;
  --f7-message-bubble-border-radius: 16px;
  --f7-message-bubble-padding-vertical: 6px;
  --f7-message-bubble-padding-horizontal: 16px;
  --f7-message-typing-indicator-opacity: 0.35;
}
.md {
  --f7-messages-title-font-size: 12px;
  --f7-message-avatar-size: 32px;
  --f7-message-margin: 16px;
  --f7-message-bubble-min-height: 32px;
  --f7-message-bubble-font-size: 16px;
  --f7-message-bubble-border-radius: 4px;
  --f7-message-bubble-padding-vertical: 6px;
  --f7-message-bubble-padding-horizontal: 8px;
  --f7-message-typing-indicator-opacity: 0.6;
  --f7-messages-title-text-color: rgba(0, 0, 0, 0.51);
  --f7-message-header-text-color: rgba(0, 0, 0, 0.51);
  --f7-message-footer-text-color: rgba(0, 0, 0, 0.51);
  --f7-message-name-text-color: rgba(0, 0, 0, 0.51);
}
.aurora {
  --f7-messages-title-font-size: 14px;
  --f7-message-avatar-size: 32px;
  --f7-message-margin: 16px;
  --f7-message-bubble-min-height: 34px;
  --f7-message-bubble-font-size: 16px;
  --f7-message-bubble-line-height: 1.4;
  --f7-message-bubble-border-radius: 16px;
  --f7-message-bubble-padding-vertical: 6px;
  --f7-message-bubble-padding-horizontal: 10px;
  --f7-message-typing-indicator-opacity: 0.5;
  --f7-message-header-font-size: 14px;
  --f7-message-footer-font-size: 12px;
  --f7-message-name-font-size: 14px;
  --f7-messages-title-text-color: rgba(0, 0, 0, 0.51);
  --f7-message-header-text-color: rgba(0, 0, 0, 0.51);
  --f7-message-footer-text-color: rgba(0, 0, 0, 0.51);
  --f7-message-name-text-color: rgba(0, 0, 0, 0.51);
}

Examples

<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner">
        <div class="title">Messages</div>
      </div>
    </div>
    <div class="toolbar messagebar">
      <div class="toolbar-inner">
        <div class="messagebar-area">
          <textarea class="resizable" placeholder="Message"></textarea>
        </div>
        <a class="link send-link" href="#" @click=${sendMessage}>Send</a>
      </div>
    </div>
    <div class="page-content messages-content">
      <div class="messages">
        <div class="messages-title"><b>Sunday, Feb 9,</b> 12:58</div>
        <div class="message message-sent">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg)"></div>
          <div class="message-content">
            <div class="message-name">John Doe</div>
            <div class="message-header">Message header</div>
            <div class="message-bubble">
              <div class="message-text-header">Text header</div>
              <div class="message-text">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
              <div class="message-text-footer">Text footer</div>
            </div>
            <div class="message-footer">Message footer</div>
          </div>
        </div>
        <div class="message message-received">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg)"></div>
          <div class="message-content">
            <div class="message-name">John Doe</div>
            <div class="message-header">Message header</div>
            <div class="message-bubble">
              <div class="message-text-header">Text header</div>
              <div class="message-text">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
              <div class="message-text-footer">Text footer</div>
            </div>
            <div class="message-footer">Message footer</div>
          </div>
        </div>
        <div class="message message-sent">
          <div class="message-content">
            <div class="message-bubble">
              <div class="message-text">Hi, Kate</div>
            </div>
          </div>
        </div>
        <div class="message message-sent">
          <div class="message-content">
            <div class="message-bubble">
              <div class="message-text">How are you?</div>
            </div>
          </div>
        </div>
        <div class="message message-received">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-9.jpg)"></div>
          <div class="message-content">
            <div class="message-name">Kate</div>
            <div class="message-bubble">
              <div class="message-text">Hi, I am good!</div>
            </div>
          </div>
        </div>
        <div class="message message-received">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg)"></div>
          <div class="message-content">
            <div class="message-name">Blue Ninja</div>
            <div class="message-bubble">
              <div class="message-text">Hi there, I am also fine, thanks! And how are you?</div>
            </div>
          </div>
        </div>
        <div class="message message-sent">
          <div class="message-content">
            <div class="message-bubble">
              <div class="message-text">Hey, Blue Ninja! Glad to see you ;)</div>
            </div>
          </div>
        </div>
        <div class="message message-sent">
          <div class="message-content">
            <div class="message-bubble">
              <div class="message-text">Hey, look, cutest kitten ever!</div>
            </div>
          </div>
        </div>
        <div class="message message-sent">
          <div class="message-content">
            <div class="message-bubble">
              <div class="message-image">
                <img src="https://cdn.framework7.io/placeholder/cats-200x260-4.jpg"
                  style="width:200px; height: 260px" />
              </div>
            </div>
          </div>
        </div>
        <div class="message message-received">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-9.jpg)"></div>
          <div class="message-content">
            <div class="message-name">Kate</div>
            <div class="message-bubble">
              <div class="message-text">Nice!</div>
            </div>
          </div>
        </div>
        <div class="message message-received">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-9.jpg)"></div>
          <div class="message-content">
            <div class="message-name">Kate</div>
            <div class="message-bubble">
              <div class="message-text">Like it very much!</div>
            </div>
          </div>
        </div>
        <div class="message message-received">
          <div class="message-avatar"
            style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg)"></div>
          <div class="message-content">
            <div class="message-name">Blue Ninja</div>
            <div class="message-bubble">
              <div class="message-text">Awesome!</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $, $on }) => {
    let messages;
    let messagebar;

    // Response flag
    var responseInProgress = false;

    // Dummy response
    var answers = [
      'Yes!',
      'No',
      'Hm...',
      'I am not sure',
      'And what about you?',
      'May be ;)',
      'Lorem ipsum dolor sit amet, consectetur',
      'What?',
      'Are you sure?',
      'Of course',
      'Need to think about it',
      'Amazing!!!'
    ]
    var people = [
      {
        name: 'Kate Johnson',
        avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg'
      },
      {
        name: 'Blue Ninja',
        avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg'
      }
    ];

    // Receive Message
    const receiveMessage = () => {
      responseInProgress = true;
      setTimeout(function () {
        // Get random answer and random person
        var answer = answers[Math.floor(Math.random() * answers.length)];
        var person = people[Math.floor(Math.random() * people.length)];

        // Show typing indicator
        messages.showTyping({
          header: person.name + ' is typing',
          avatar: person.avatar
        });

        setTimeout(function () {
          // Add received dummy message
          messages.addMessage({
            text: answer,
            type: 'received',
            name: person.name,
            avatar: person.avatar
          });
          // Hide typing indicator
          messages.hideTyping();
          responseInProgress = false;
        }, 4000);
      }, 1000);
    }

    // Send Message
    const sendMessage = () => {
      var text = messagebar.getValue().replace(/\n/g, '<br>').trim();
      // return if empty message
      if (!text.length) return;

      // Clear area
      messagebar.clear();

      // Return focus to area
      messagebar.focus();

      // Add message to messages
      messages.addMessage({
        text: text,
      });

      if (responseInProgress) return;
      // Receive dummy message
      receiveMessage();
    }

    $on('pageInit', () => {
      // Init Messages
      messages = app.messages.create({
        el: '.messages',

        // First message rule
        firstMessageRule: function (message, previousMessage, nextMessage) {
          // Skip if title
          if (message.isTitle) return false;
          /* if:
            - there is no previous message
            - or previous message type (send/received) is different
            - or previous message sender name is different
          */
          if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
          return false;
        },
        // Last message rule
        lastMessageRule: function (message, previousMessage, nextMessage) {
          // Skip if title
          if (message.isTitle) return false;
          /* if:
            - there is no next message
            - or next message type (send/received) is different
            - or next message sender name is different
          */
          if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
          return false;
        },
        // Last message rule
        tailMessageRule: function (message, previousMessage, nextMessage) {
          // Skip if title
          if (message.isTitle) return false;
          /* if (basically same as lastMessageRule):
          - there is no next message
          - or next message type (send/received) is different
          - or next message sender name is different
        */
          if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
          return false;
        }
      });

      // Init Messagebar
      messagebar = app.messagebar.create({
        el: '.messagebar'
      });
    });

    return $render;
  }



</script>