Messagebar

Framework7 comes with special resizable toolbar for usage with Messages

Messagebar Layout

Messagebar layout is pretty simple:

<div class="toolbar messagebar">
  <div class="toolbar-inner">
    <div class="messagebar-area">
      <!-- messagebar attachments -->
      <div class="messagebar-attachments">...</div>
      <!-- messagebar resizable textarea -->
      <textarea class="resizable" placeholder="Message"></textarea>
    </div>
    <a href="#" class="link">Send</a>
  </div>
  <!-- messagebar sheet -->
  <div class="messagebar-sheet">...</div>
</div>

Where

Messagebar place is very important, it should be inside of page and right before page-content:

<div class="page">
  <!-- navbar -->
  <div class="navbar">...</div>

  <!-- messagebar -->
  <div class="toolbar messagebar">...</div>

  <!-- page-content/messages-content -->
  <div class="page-content messages-content">
    ... messages
  </div>
</div>

Messagebar Sheet Layout

If need additional sheet with, for example, images that we can attach to message then we use extra block designed for this:

<div class="messagebar-sheet">
  <!-- selectable sheet image -->
  <label class="checkbox messagebar-sheet-image" style="background-image:url(path/to/image1.png)">
    <input type="checkbox" />
    <i class="icon icon-checkbox"></i>
  </label>

  <!-- another selectable sheet image -->
  <label class="checkbox messagebar-sheet-image" style="background-image:url(path/to/image2.png)">
    <input type="checkbox" />
    <i class="icon icon-checkbox"></i>
  </label>

  <!-- some custom sheet item -->
  <div class="messagebar-sheet-item">
    <!-- any custom content here -->
  </div>
</div>

Messagebar Attachments Layout

Messages attachments block is designed to display currently attached message items/images:

<div class="messagebar-attachments">
  <!-- image attachment -->
  <div class="messagebar-attachment">
    <img src="path/to/image1.png" />
  </div>

  <!-- deletable image attachment -->
  <div class="messagebar-attachment">
    <img src="path/to/image2.png" />
    <!-- attachment delete button -->
    <span class="messagebar-attachment-delete"></span>
  </div>
</div>

Messagebar App Methods

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

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

Messagebar Parameters

Let's look on list of all available parameters:

ParameterTypeDefaultDescription
elstring
HTMLElement
CSS selector or HTML element of messagebar element (div class="messagebar")
textareaElstring
HTMLElement
CSS selector or HTML element of messagebar textarea element. By default (if not passed) will try to look for textarea inside of messagebar
maxHeightnumbernullMax height of textarea when it resized depending on amount of its text
attachmentsarray[]Array with attachments. For example ['path/to/image1.png', 'path/to/image2.png']
resizePagebooleantrueDisable if you don't want to resize messages page when messagebar textarea size changed
onobject

Object with events handlers. For example:

var messagebar = app.messagebar.create({
  el: '.messagebar',
  on: {
    change: function () {
      console.log('Textarea value changed')
    }
  }
})
Render functions
renderAttachmentsfunction(attachments)Function to render attachments block. Must return full attachments HTML string
renderAttachmentfunction(attachment)Function to render single attachment. Must return full attachment HTML string

Messagebar Methods & Properties

So to create Messagebar we have to call:

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

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

Properties
messagebar.elMessagebar HTML element.
messagebar.$elDom7 element with messagebar HTML element.
messagebar.textareaElMessagebar textarea HTML element
messagebar.$textareaElDom7 element with messagebar textarea HTML element
messagebar.paramsObject with passed initialization parameters
messagebar.attachmentsArray with messagebar attachments
Methods
messagebar.getValue();Get messagebar textarea value
messagebar.setValue(value);Set messagebar textarea value/text
messagebar.clear();Clear textarea and update/reset its size
messagebar.focus();Focus messagebar textarea
messagebar.blur();Remove focus from messagebar textarea
messagebar.setPlaceholder(placeholder)Set/change messagebar placeholder text
messagebar.resizePage()Force Messagebar to resize messages page depending on messagebar height/size
messagebar.attachmentsCreate()Dynamically create attachments block HTML element
messagebar.attachmentsShow()Show attachments block
messagebar.attachmentsHide()Hide attachments block
messagebar.attachmentsToggle()Toggle attachments block
messagebar.renderAttachments()Render attachments block based on attachments data
messagebar.sheetCreate()Dynamically create messagebar sheet block HTML element
messagebar.sheetShow()Show messagebar sheet
messagebar.sheetHide()Hide messagebar sheet
messagebar.sheetToggle()Toggle messagebar sheet
messagebar.destroy();Destroy messagebar instance

Messagebar Events

Messagebar will fire the following DOM events on messagebar element and events on app and messagebar instance:

DOM Events

EventTargetDescription
messagebar:changeMessagebar Element<div class="messagebar">Event will be triggered after messagebar textarea value changed
messagebar:focusMessagebar Element<div class="messagebar">Event will be triggered when messagebar textarea gets focus
messagebar:blurMessagebar Element<div class="messagebar">Event will be triggered when messagebar textarea loses focus
messagebar:resizepageMessagebar Element<div class="messagebar">Event will be triggered when messagebar resizes messages page
messagebar:attachmentdeleteMessagebar attachment element<div class="messagebar-attachment">Event will be triggered after click on messagebar attachment delete button
messagebar:attachmentclickMessagebar attachment element<div class="messagebar-attachment">Event will be triggered on messagebar attachment click
messagebar:beforedestroyMessagebar Element<div class="messagebar">Event will be triggered right before Messagebar instance will be destroyed

App and Messagebar Instance Events

Messagebar instance emits events on both self instance and app instance. App instance events has same names prefixed with messagebar.

EventTargetArgumentsDescription
changemessagebar(messagebar)Event will be triggered after messagebar textarea value changed. As an argument event handler receives messagebar instance
messagebarChangeapp
focusmessagebar(messagebar)Event will be triggered when messagebar textarea gets focus. As an argument event handler receives messagebar instance
messagebarFocusapp
blurmessagebar(messagebar)Event will be triggered when messagebar textarea loses focus. As an argument event handler receives messagebar instance
messagebarBlurapp
resizePagemessagebar(messagebar)Event will be triggered when messagebar resizes messages page. As an argument event handler receives messagebar instance
messagebarResizePageapp
attachmentDeletemessagebar(messagebar, attachmentEl, attachmentIndex)Event will be triggered after click on messagebar attachment delete button. As an argument event handler receives messagebar instance, clicked attachment HTML element and attachment index number
messagebarAttachmentDeleteapp
attachmentClickmessagebar(messagebar, attachmentEl, attachmentIndex)Event will be triggered on messagebar attachment click. As an argument event handler receives messagebar instance, clicked attachment HTML element and attachment index number
messagebarAttachmentClickapp
beforeDestroymessagebar(messagebar)Event will be triggered right before Messagebar instance will be destroyed
messagebarBeforeDestroyapp

Messagebar Auto Initialization

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

<div class="toolbar messagebar messagebar-init" data-max-height="200">
  <div class="toolbar-inner">
    <div class="messagebar-area">
      <textarea placeholder="Message"></textarea>
    </div>
    <a href="#" class="link">Send</a>
  </div>
</div>

Parameters that used in camelCase, for example maxHeight, in data- attributes should be used in kebab-case as data-max-height

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-messagebar-attachments-height: 155px;
  --f7-messagebar-sheet-height: 252px;
  --f7-messagebar-sheet-landscape-height: 192px;
  /*
  --f7-messagebar-inner-padding-left: var(--f7-toolbar-inner-padding-left);
  --f7-messagebar-inner-padding-right: var(--f7-toolbar-inner-padding-right);
  */
}
.ios {
  --f7-messagebar-height: 44px;
  --f7-messagebar-font-size: 17px;
  --f7-messagebar-textarea-bg-color: transparent;
  /*
  --f7-messagebar-link-color: var(--f7-theme-color);
  */
  --f7-messagebar-border-color: transparent;
  --f7-messagebar-textarea-border-radius: 17px;
  --f7-messagebar-textarea-padding: 6px 16px;
  --f7-messagebar-textarea-height: 34px;
  --f7-messagebar-textarea-font-size: 17px;
  --f7-messagebar-textarea-line-height: 20px;
  --f7-messagebar-sheet-bg-color: #d1d5da;
  --f7-messagebar-sheet-border-color: transparent;
  --f7-messagebar-attachment-border-radius: 12px;
  --f7-messagebar-attachment-height: 155px;
  --f7-messagebar-attachment-landscape-height: 120px;
  --f7-messagebar-textarea-placeholder-color: rgba(0, 0, 0, 0.4);
  --f7-messagebar-textarea-text-color: #000;
  --f7-messagebar-textarea-border: 1px solid #c8c8cd;
  --f7-messagebar-attachments-border-color: #c8c8cd;
  --f7-messagebar-bg-color: #fff;
  --f7-messagebar-bg-color-rgb: 255, 255, 255;
}
.ios .dark,
.ios.dark {
  --f7-messagebar-textarea-placeholder-color: rgba(255, 255, 255, 0.4);
  --f7-messagebar-textarea-text-color: #fff;
  --f7-messagebar-textarea-border: 1px solid var(--f7-bars-border-color);
  --f7-messagebar-attachments-border-color: var(--f7-bars-border-color);
  --f7-messagebar-bg-color: var(--f7-bars-bg-color);
  --f7-messagebar-bg-color-rgb: var(--f7-bars-bg-color-rgb);
}
.md {
  --f7-messagebar-height: 64px;
  --f7-messagebar-font-size: 16px;
  --f7-messagebar-textarea-border-radius: 24px;
  --f7-messagebar-textarea-padding: 12px 16px;
  --f7-messagebar-textarea-height: 48px;
  --f7-messagebar-textarea-font-size: 16px;
  --f7-messagebar-textarea-line-height: 22px;
  --f7-messagebar-textarea-border: 1px solid transparent;
  --f7-messagebar-attachment-border-radius: 12px;
  --f7-messagebar-attachment-height: 72px;
  --f7-messagebar-attachment-landscape-height: 72px;
  --f7-messagebar-border-color: transparent;
  --f7-messagebar-attachments-border-color: transparent;
}
.md,
.md .dark,
.md [class*='color-'] {
  --f7-messagebar-textarea-placeholder-color: var(--f7-md-on-surface-variant);
  --f7-messagebar-textarea-bg-color: var(--f7-md-surface-variant);
  --f7-messagebar-bg-color: var(--f7-md-surface);
  --f7-messagebar-textarea-text-color: var(--f7-md-on-surface);
  --f7-messagebar-sheet-bg-color: var(--f7-md-surface);
  --f7-messagebar-sheet-border-color: var(--f7-md-outline-variant);
  --f7-messagebar-link-color: var(--f7-md-on-surface);
}

Examples

messages.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Messages</div>
      </div>
    </div>
    <div class="toolbar messagebar" @messagebar:attachmentdelete=${deleteAttachment}>
      <div class="toolbar-inner">
        <a class="link icon-only" @click=${sheetToggle}>
          <i class="icon f7-icons if-not-md">camera_fill</i>
          <i class="icon material-icons md-only">camera_alt</i>
        </a>
        <div class="messagebar-area">
          <textarea class="resizable" placeholder="Message"></textarea>
        </div>
        <a class="link icon-only demo-send-message-link" @click=${sendMessage}>
          <i class="icon f7-icons if-not-md">arrow_up_circle_fill</i>
          <i class="icon material-icons md-only">send</i>
        </a>
      </div>
      <div class="messagebar-sheet">
        ${images.map((image) => $h`
        <label class="checkbox messagebar-sheet-image" @change=${handleAttachment}>
          <input type="checkbox" />
          <i class="icon icon-checkbox"></i>
          <img src=${image} />
        </label>
        `)}
      </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-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, $el, $on, $ }) => {
    const images = [
      'https://cdn.framework7.io/placeholder/cats-300x300-1.jpg',
      'https://cdn.framework7.io/placeholder/cats-200x300-2.jpg',
      'https://cdn.framework7.io/placeholder/cats-400x300-3.jpg',
      'https://cdn.framework7.io/placeholder/cats-300x150-4.jpg',
      'https://cdn.framework7.io/placeholder/cats-150x300-5.jpg',
      'https://cdn.framework7.io/placeholder/cats-300x300-6.jpg',
      'https://cdn.framework7.io/placeholder/cats-300x300-7.jpg',
      'https://cdn.framework7.io/placeholder/cats-200x300-8.jpg',
      'https://cdn.framework7.io/placeholder/cats-400x300-9.jpg',
      'https://cdn.framework7.io/placeholder/cats-300x150-10.jpg'
    ];
    const 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'
      },
    ];
    const 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!!!',
    ];

    let responseInProgress = false;
    let messagebar;
    let messages;

    const sheetToggle = () => {
      messagebar.sheetToggle();
    }
    const deleteAttachment = (e, index) => {
      var image = messagebar.attachments.splice(index, 1)[0];
      messagebar.renderAttachments();
      checkAttachments();
      // Uncheck in sheet
      var imageIndex = images.indexOf(image);
      $el.value.find('.messagebar-sheet .checkbox').eq(imageIndex).find('input').prop('checked', false);
    }
    const handleAttachment = (e) => {
      var index = $(e.target).parents('label.checkbox').index();
      var image = images[index];
      if (e.target.checked) {
        // Add to attachments
        messagebar.attachments.unshift(image)
      } else {
        // Remove from attachments
        messagebar.attachments.splice(messagebar.attachments.indexOf(image), 1);
      }
      messagebar.renderAttachments();
      checkAttachments();
    }
    const checkAttachments = () => {
      if (messagebar.attachments.length > 0) {
        messagebar.attachmentsShow();
        messagebar.setPlaceholder('Add comment or Send');
      } else {
        messagebar.attachmentsHide();
        messagebar.setPlaceholder('Message');
      }
    }
    const sendMessage = () => {
      var text = messagebar.getValue().replace(/\n/g, '<br />').trim();
      var messagesToSend = [];
      messagebar.attachments.forEach(function (attachment) {
        var size = attachment.split('placeholder/cats-')[1].split('-')[0].split('x');
        messagesToSend.push({
          image: '<img src="' + attachment + '" style="width: ' + (size[0] / 2) + 'px; height: ' + (size[1] / 2) + 'px">'
        });
      });
      if (text.trim().length) {
        messagesToSend.push({
          text: text
        });
      }
      // Reset attachments
      messagebar.attachments = [];
      checkAttachments();
      // Hide sheet
      messagebar.sheetHide();
      // Uncheck selected images in sheet
      messagebar.$sheetEl.find('input').prop('checked', false);
      // Clear area
      messagebar.clear();
      // Focus area
      if (text.length) messagebar.focus();
      // Exit when nothing to send
      if (!messagesToSend.length) return;
      // Send message
      messages.addMessages(messagesToSend);

      // Mock response
      if (responseInProgress) return;
      responseInProgress = true;
      setTimeout(function () {
        var answer = answers[Math.floor(Math.random() * answers.length)];
        var person = people[Math.floor(Math.random() * people.length)];
        messages.showTyping({
          header: person.name + ' is typing',
          avatar: person.avatar
        });
        setTimeout(function () {
          messages.addMessage({
            text: answer,
            type: 'received',
            name: person.name,
            avatar: person.avatar
          });
          messages.hideTyping();
          responseInProgress = false;
        }, 4000);
      }, 1000);
    }

    $on('pageInit', () => {
      messagebar = $f7.messagebar.create({
        el: $el.value.find('.messagebar'),
        attachments: []
      });
      messages = $f7.messages.create({
        el: $el.value.find('.messages'),
        firstMessageRule: function (message, previousMessage, nextMessage) {
          if (message.isTitle) return false;
          if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
          return false;
        },
        lastMessageRule: function (message, previousMessage, nextMessage) {
          if (message.isTitle) return false;
          if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
          return false;
        },
        tailMessageRule: function (message, previousMessage, nextMessage) {
          if (message.isTitle) return false;
          if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
          return false;
        }
      });
    })
    $on('pageBeforeRemove', () => {
      messagebar.destroy()
      messages.destroy()
    })



    return $render;
  };

</script>