> For the complete documentation index, see [llms.txt](https://docs.quantumbyte.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.quantumbyte.ai/home/quantumbyte-v2.0/3.microsites-1/8.ui/4.components/messages.md).

# Messages

### Messages Props <a href="#messages-props" id="messages-props"></a>

| Name      | Type   | Default | Description              |
| --------- | ------ | ------- | ------------------------ |
| component | string | 'div'   | Component's HTML Element |

### Message Props

<table><thead><tr><th>Name</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td>avatar</td><td>string</td><td></td><td>Message user's avatar URL</td></tr><tr><td>colors</td><td>object</td><td></td><td></td></tr><tr><td>colors.bubbleReceivedIos</td><td>string</td><td>'bg-[#e5e5ea] dark:bg-[#252525]'</td><td></td></tr><tr><td>colors.bubbleReceivedMd</td><td>string</td><td>'dark:bg-md-dark-surface-variant bg-[#e5e5ea]'</td><td></td></tr><tr><td>colors.bubbleSentIos</td><td>string</td><td>'bg-primary'</td><td></td></tr><tr><td>colors.bubbleSentMd</td><td>string</td><td>'bg-md-light-primary dark:bg-md-dark-primary dark:text-md-dark-on-primary'</td><td></td></tr><tr><td>colors.messageNameIos</td><td>string</td><td>'text-black text-opacity-45 dark:text-white dark:text-opacity-45'</td><td></td></tr><tr><td>colors.messageNameMd</td><td>string</td><td>'text-md-light-on-surface-variant dark:text-md-dark-on-surface-variant'</td><td></td></tr><tr><td>colors.messageSent</td><td>string</td><td>'text-white'</td><td></td></tr><tr><td>component</td><td>string</td><td>'div'</td><td>Component's HTML Element</td></tr><tr><td>footer</td><td>string</td><td></td><td>Content of the Message footer</td></tr><tr><td>header</td><td>string</td><td></td><td>Content of the Message header</td></tr><tr><td>id</td><td>string</td><td></td><td>Message id attribute</td></tr><tr><td>name</td><td>string</td><td></td><td>Message name</td></tr><tr><td>text</td><td>string</td><td></td><td>Message text</td></tr><tr><td>textFooter</td><td>string</td><td></td><td>Message footer text</td></tr><tr><td>textHeader</td><td>string</td><td></td><td>Message header text</td></tr><tr><td>type</td><td>string</td><td>'sent'</td><td><pre><code>Message type: sent (default) or received
</code></pre></td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td></tr></tbody></table>

### Message Slots

| Name   | Description                   |
| ------ | ----------------------------- |
| avatar | Message user's avatar URL     |
| footer | Content of the Message footer |
| header | Content of the Message header |

### MessagesTitle Props

| Name           | Type   | Default                                                                 | Description              |
| -------------- | ------ | ----------------------------------------------------------------------- | ------------------------ |
| colors         | object |                                                                         |                          |
| colors.titleMd | string | 'text-md-light-on-surface-variant dark:text-md-dark-on-surface-variant' |                          |
| component      | string | 'div'                                                                   | Component's HTML Element |

## Examples

{% tabs %}
{% tab title="Vue" %}

```typescript
<template>
  <k-page class="ios:bg-white ios:dark:bg-black messages-page">
    <k-navbar title="Messages" />
    <k-messages>
      <k-messages-title
        ><b>{{ currentDay }}</b
        >, {{ currentTime }}</k-messages-title
      >
      <k-message
        v-for="(message, index) in messagesData"
        :key="index"
        :type="message.type"
        :name="message.name"
        :text="message.text"
      >
        <template v-if="message.type === 'received'" #avatar>
          <img
            alt="avatar"
            class="w-8 h-8 rounded-full"
            :src="message.avatar"
          />
        </template>
      </k-message>
    </k-messages>
    <k-messagebar
      placeholder="Message"
      :value="messageText"
      @input="onMessageTextChange"
    >
      <template #left>
        <k-link toolbar icon-only>
          <k-icon>
            <template #ios><CameraFill class="w-7 h-7" /></template>
            <template #material>
              <MdCameraAlt
                class="w-6 h-6 fill-black dark:fill-md-dark-on-surface"
              />
            </template>
          </k-icon>
        </k-link>
      </template>
      <template #right>
        <k-link
          toolbar
          :style="{
            opacity: inputOpacity,
            cursor: isClickable ? 'pointer' : 'default',
          }"
          @click="onClick"
        >
          <k-icon>
            <template #ios><ArrowUpCircleFill class="w-7 h-7" /></template>
            <template #material>
              <MdSend class="w-6 h-6 fill-black dark:fill-md-dark-on-surface" />
            </template>
          </k-icon>
        </k-link>
      </template>
    </k-messagebar>
  </k-page>
</template>
<script>
  import { ref, onMounted, watch, nextTick } from 'vue';
  import {
    kPage,
    kNavbar,
    kNavbarBackLink,
    kMessagebar,
    kMessages,
    kMessage,
    kMessagesTitle,
    kIcon,
    kLink,
  } from 'konsta/vue';
  import { CameraFill, ArrowUpCircleFill } from 'framework7-icons/vue';
  import MdCameraAlt from '../components/MdCameraAlt.vue';
  import MdSend from '../components/MdSend.vue';

  export default {
    components: {
      kPage,
      kNavbar,
      kNavbarBackLink,
      kMessagebar,
      kMessages,
      kMessage,
      kMessagesTitle,
      kIcon,
      kLink,

      CameraFill,
      ArrowUpCircleFill,
      MdCameraAlt,
      MdSend,
    },
    setup() {
      const messageText = ref('');
      const isClickable = ref(false);
      const inputOpacity = ref(0.3);

      const onMessageTextChange = (e) => {
        messageText.value = e.target.value;
        isClickable.value = messageText.value.trim().length > 0;
      };

      watch(messageText, (newValue) => {
        inputOpacity.value = newValue ? 1 : 0.3;
      });

      const messagesData = ref([
        {
          type: 'sent',
          text: 'Hi, Kate',
        },
        {
          type: 'sent',
          text: 'How are you?',
        },
        {
                type: 'received',
          text: 'Hi, I am good!',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
          name: 'Blue Ninja',
          type: 'received',
          text: 'Hi there, I am also fine, thanks! And how are you?',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
        },
        {
          type: 'sent',
          text: 'Hey, Blue Ninja! Glad to see you ;)',
        },
        {
          type: 'sent',
          text: 'How do you feel about going to the movies today?',
        },
        {
                type: 'received',
          text: ' Oh, great idea!',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
                type: 'received',
          text: ' What cinema are we going to?',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
          name: 'Blue Ninja',
          type: 'received',
          text: 'Great. And what movie?',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
        },
        {
          name: 'Blue Ninja',
          type: 'received',
          text: 'What time?',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
        },
      ]);
      const scrollToBottom = (animate = true) => {
        const pageEl = document.querySelector('.messages-page');
        pageEl.scrollTo({
          top: pageEl.scrollHeight - pageEl.offsetHeight,
          behavior: animate ? 'smooth' : 'auto',
        });
      };
      onMounted(() => scrollToBottom(false));
      watch(messagesData, () => {
        scrollToBottom();
      });

      const handleSendClick = () => {
        const text = messageText.value.replace(/
/g, '<br>').trim();
        const type = 'sent';
        const messagesToSend = [];

        if (text.length) {
          messagesToSend.push({
            text,
            type,
          });

          console.log(messagesToSend);
        }

        if (messagesToSend.length === 0) {
          return;
        }

        messagesData.value.push(...messagesToSend);
        messageText.value = '';

        nextTick(() => {
          scrollToBottom();
        });
      };

      const onClick = () => {
        if (isClickable.value) {
          handleSendClick();
        }
      };

      const dateFormatter = new Intl.DateTimeFormat('en-US', {
        weekday: 'long',
        month: 'short',
        day: 'numeric',
      });

      const timeFormatter = new Intl.DateTimeFormat('en-US', {
        hour12: false,
        hour: '2-digit',
        minute: '2-digit',
      });

      const currentDate = new Date();
      const currentDay = dateFormatter.format(currentDate);
      const currentTime = timeFormatter.format(currentDate);

      return {
        onClick,
        messageText,
        messagesData,
        onMessageTextChange,
        handleSendClick,
        inputOpacity,
        isClickable,
        currentDay,
        currentTime,
      };
    },
  };
</script>
```

{% endtab %}

{% tab title="React" %}

```javascript
/* eslint-disable react/no-array-index-key */
import { React, useState, useRef, useEffect } from 'react';
import {
  Page,
  Navbar,
  NavbarBackLink,
  Messagebar,
  Messages,
  Message,
  MessagesTitle,
  Link,
  Icon,
} from 'konsta/react';
import { CameraFill, ArrowUpCircleFill } from 'framework7-icons/react';
import { MdCameraAlt, MdSend } from 'react-icons/md';

export default function MessagesPage() {
  const [messageText, setMessageText] = useState('');
  const [messagesData, setMessagesData] = useState([
    {
      type: 'sent',
      text: 'Hi, Kate',
    },
    {
      type: 'sent',
      text: 'How are you?',
    },
    {
      name: 'Kate',
      type: 'received',
      text: 'Hi, I am good!',
      avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
    },
    {
      name: 'Blue Ninja',
      type: 'received',
      text: 'Hi there, I am also fine, thanks! And how are you?',
      avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
    },
    {
      type: 'sent',
      text: 'Hey, Blue Ninja! Glad to see you ;)',
    },
    {
      type: 'sent',
      text: 'How do you feel about going to the movies today?',
    },
    {
      name: 'Kate',
      type: 'received',
      text: ' Oh, great idea!',
      avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
    },
    {
      name: 'Kate',
      type: 'received',
      text: ' What cinema are we going to?',
      avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
    },
    {
      name: 'Blue Ninja',
      type: 'received',
      text: 'Great. And what movie?',
      avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
    },
    {
      name: 'Blue Ninja',
      type: 'received',
      text: 'What time?',
      avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
    },
  ]);

  const pageRef = useRef();
  const initiallyScrolled = useRef(false);

  const scrollToBottom = () => {
    const pageElement = pageRef.current.current || pageRef.current.el;
    pageElement.scrollTo({
      top: pageElement.scrollHeight - pageElement.offsetHeight,
      behavior: initiallyScrolled.current ? 'smooth' : 'auto',
    });
  };

  useEffect(() => {
    scrollToBottom();
    initiallyScrolled.current = true;
  }, [messagesData]);

  const handleSendClick = () => {
    const text = messageText.replace(/
/g, '<br>').trim();
    const type = 'sent';
    const messagesToSend = [];
    if (text.length) {
      messagesToSend.push({
        text,
        type,
      });
    }
    if (messagesToSend.length === 0) {
      return;
    }
    setMessagesData([...messagesData, ...messagesToSend]);
    setMessageText('');
  };

  const inputOpacity = messageText ? 1 : 0.3;
  const isClickable = messageText.trim().length > 0;

  const currentDate = new Intl.DateTimeFormat('en-US', {
    weekday: 'long',
    month: 'short',
    day: 'numeric',
    hour12: false,
    hour: '2-digit',
    minute: '2-digit',
  })
    .formatToParts(new Date())
    .map((part) => {
      if (['weekday', 'month', 'day'].includes(part.type)) {
        return <b key={part.type}>{part.value}</b>;
      }
      return part.value;
    });

  return (
    <Page className="ios:bg-white ios:dark:bg-black" ref={pageRef}>
      <Navbar
        title="Messages"
        />
      <Messages>
        <MessagesTitle>{currentDate}</MessagesTitle>
        {messagesData.map((message, index) => (
          <Message
            key={index}
            type={message.type}
            name={message.name}
            text={message.text}
            avatar={
              message.type === 'received' && (
                <img
                  alt="avatar"
                  src={message.avatar}
                  className="w-8 h-8 rounded-full"
                />
              )
            }
          />
        ))}
      </Messages>
      <Messagebar
        placeholder="Message"
        value={messageText}
        onInput={(e) => setMessageText(e.target.value)}
        left={
          <Link onClick={() => console.log('click')} toolbar iconOnly>
            <Icon
              ios={<CameraFill className="w-7 h-7" />}
              material={
                <MdCameraAlt className="w-6 h-6 fill-black dark:fill-md-dark-on-surface" />
              }
            />
          </Link>
        }
        right={
          <Link
            onClick={isClickable ? handleSendClick : undefined}
            toolbar
            style={{
              opacity: inputOpacity,
              cursor: isClickable ? 'pointer' : 'default',
            }}
          >
            <Icon
              ios={<ArrowUpCircleFill className="w-7 h-7" />}
              material={
                <MdSend className="w-6 h-6 fill-black dark:fill-md-dark-on-surface" />
              }
            />
          </Link>
        }
      />
    </Page>
  );
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.quantumbyte.ai/home/quantumbyte-v2.0/3.microsites-1/8.ui/4.components/messages.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
