JSFiddle - React, Tailwind, and code Playground

by Simon Herteby

HTML

<div id="vue">
  <div v-if="topLabel" class="label toplabel" v-html="topLabel"></div>
  <template v-for="message, i in messages">
    <div class="label" v-if="diff(i)" ref="labels">{{message.date.toDateString()}}</div>
    <div class="message">
      {{message.date.toLocaleTimeString()}} {{message.text}} 
    </div>
  </template>
</div>

CSS

body{
  margin:0;
  overflow:hidden;
}
#vue{
  max-height:100vh;
  overflow:auto;
}
.label{
  background:rgba(0,0,0,0.5);
  color:white;
  padding:5px;
  text-align:center;
}
.toplabel{
  position:absolute;
  width:100%;
  top:0px
}
.message{
  background:white;
  border-radius:99px;
  margin:10px;
  padding:10px;
}

JavaScript

let messages = []
let hour = 1000 * 60 * 60
for(let i = 0; i < 40; i+= Math.random()){
	messages.push({text:'Hello', date:new Date(Date.now() + i * 3 * hour)})
}
new Vue({
	el:'#vue',
  data:{
  	messages:messages,
    topLabel:undefined
  },
  methods:{
  	diff(i){
    	let current = this.messages[i]
      let prev = this.messages[i - 1]
      return !prev || (prev.date.toDateString() !== current.date.toDateString())
    },
    setTopLabel(){
    	let label = this.$refs.labels.sort((a, b) => a.offsetTop < b.offsetTop).find(el => el.offsetTop < this.$el.scrollTop)
      this.topLabel = label && label.innerHTML
    }
  },
  mounted(){
  	this.setTopLabel()
    this.$el.addEventListener('scroll', this.setTopLabel)
  }
})