#app.container
	button(v-on:click="openToast('default')").default Open 'Default'
	button(v-on:click="openToast('primary')").primary Open 'Primary'
	button(v-on:click="openToast('success')").success Open 'Success'
	button(v-on:click="openToast('warning')").warning Open 'Warning'
	button(v-on:click="openToast('danger')").danger Open 'Danger'
	a-lil-toast(v-bind:messages.sync="messages")
View Compiled
$font-family: Montserrat, sans-serif;;
$spacing: 15px;

$a-lil-toast-max-width: 500px;
$a-lil-toast-padding: 0 20px;
$a-lil-toast-bottom: $spacing;

$a-lil-toast-message-default-color: #ffffff;
$a-lil-toast-message-default-background-color: #404040;
$a-lil-toast-message-padding: $spacing;
$a-lil-toast-message-margin: $spacing 0 0 0;
$a-lil-toast-message-box-shadow: 0 3px 8px rgba(#000000, 0.1);
$a-lil-toast-message-animation: a-lil-toast-show 500ms ease-in-out forwards;

$a-lil-toast-message-primary-color: #ffffff;
$a-lil-toast-message-primary-background-color: #1489ff;

$a-lil-toast-message-success-color: #ffffff;
$a-lil-toast-message-success-background-color: #00ce0d;

$a-lil-toast-message-warning-color: #4c3b03;
$a-lil-toast-message-warning-background-color: #ffe92b;

$a-lil-toast-message-danger-color: #ffffff;
$a-lil-toast-message-danger-background-color: #ff2323;

$a-lil-toast-message-closed-animation: a-lil-toast-hide 500ms ease-in-out forwards;

$a-lil-toast-control-margin-bottom: $spacing;

@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700");

.a-lil-toast {
	font-family: $font-family;
	width: 100%;
	max-width: $a-lil-toast-max-width;
	height: 0;
	padding: $a-lil-toast-padding;
	display: flex;
	flex-direction: column-reverse;
	position: fixed;
	left: 50%;
	bottom: $a-lil-toast-bottom;
	box-sizing: border-box;
	transform: translateX(-50%);
}

.a-lil-toast-message {
	width: 100%;
	margin: $a-lil-toast-message-margin;
	padding: $a-lil-toast-message-padding;
	box-sizing: border-box;
	box-shadow: $a-lil-toast-message-box-shadow;
	transform-origin: bottom center;
	&.default {
		color: $a-lil-toast-message-default-color;
		background-color: $a-lil-toast-message-default-background-color;
	}
	&.primary {
		color: $a-lil-toast-message-primary-color;
		background-color: $a-lil-toast-message-primary-background-color;
	}
	&.success {
		color: $a-lil-toast-message-success-color;
		background-color: $a-lil-toast-message-success-background-color;
	}
	&.warning {
		color: $a-lil-toast-message-warning-color;
		background-color: $a-lil-toast-message-warning-background-color;
	}
	&.danger {
		color: $a-lil-toast-message-danger-color;
		background-color: $a-lil-toast-message-danger-background-color;
	}
	&:not(.closed) {
		animation: $a-lil-toast-message-animation;
	}
	&.closed {
		animation: $a-lil-toast-message-closed-animation;
	}
}

.a-lil-toast-control {
	margin-bottom: $a-lil-toast-control-margin-bottom;
	&.title {
		font-weight: bold;
	}
	&.button {
		text-align: right;
		a {
			color: inherit;
			font-weight: bold;
			text-decoration: none;
			outline: none;
			&:hover, &:focus, &:active {
				text-decoration: underline;
			}
		}
	}
	&:last-child {
		margin-bottom: 0;
	}
}

@keyframes a-lil-toast-show {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@keyframes a-lil-toast-hide {
	from { opacity: 1; }
	to   { opacity: 0; }
}

// -----

html, body, .container {
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0
}

.container {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	button {
		font-family: $font-family;
		font-size: 24px;
		font-weight: bold;
		width: calc(100% - 30px);
		max-width: 360px;
		border: none;
		padding: 15px;
		margin: 5px;
		box-sizing: border-box;
		&.default {
			color: $a-lil-toast-message-default-color;
			background-color: $a-lil-toast-message-default-background-color;
			&:hover {
				background-color: lighten($a-lil-toast-message-default-background-color, 5%);
			}
			&:active {
				background-color: darken($a-lil-toast-message-default-background-color, 5%);
			}
		}
		&.primary {
			color: $a-lil-toast-message-primary-color;
			background-color: $a-lil-toast-message-primary-background-color;
			&:hover {
				background-color: lighten($a-lil-toast-message-primary-background-color, 5%);
			}
			&:active {
				background-color: darken($a-lil-toast-message-primary-background-color, 5%);
			}
		}
		&.success {
			color: $a-lil-toast-message-success-color;
			background-color: $a-lil-toast-message-success-background-color;
			&:hover {
				background-color: lighten($a-lil-toast-message-success-background-color, 5%);
			}
			&:active {
				background-color: darken($a-lil-toast-message-success-background-color, 5%);
			}
		}
		&.warning {
			color: $a-lil-toast-message-warning-color;
			background-color: $a-lil-toast-message-warning-background-color;
			&:hover {
				background-color: lighten($a-lil-toast-message-warning-background-color, 5%);
			}
			&:active {
				background-color: darken($a-lil-toast-message-warning-background-color, 5%);
			}
		}
		&.danger {
			color: $a-lil-toast-message-danger-color;
			background-color: $a-lil-toast-message-danger-background-color;
			&:hover {
				background-color: lighten($a-lil-toast-message-danger-background-color, 5%);
			}
			&:active {
				background-color: darken($a-lil-toast-message-danger-background-color, 5%);
			}
		}
	}
}
View Compiled
Vue.component('a-lil-toast', {
	props: ['messages'],
	data: function() {
		return {
			closeText: {
				en: 'Close',
				ja: '閉じる'
			}
		}
	},
	methods: {
		removeItem: function(id) {
			this.messages[id].closed = 'closed';
			
			this.$emit('update:messages', this.messages);
		},
		messageCloseTimer: function(evt, id, timer) {
			let el   = evt.target;
			let self = this;
			
			if (timer !== 0) {
				if (evt.animationName === 'a-lil-toast-show') {
					setTimeout(function() {
						self.removeItem(id);
					}, timer);
				}
			}
			
			if (evt.animationName === 'a-lil-toast-hide') {
				self.messages[id].content = '';

				self.messages.splice(id, 1);

				self.$emit('update:messages', self.messages);
			}
		}
	},
	template: `
<div class="a-lil-toast">
	<div class="a-lil-toast-message" v-for="(message, id) in messages" v-bind:class="[message.type, message.closed]" v-on:animationend="messageCloseTimer(event, id, (message.timer) ? message.timer : 0)">
		<div class="a-lil-toast-control title" v-if="message.title">{{ message.title }}</div>
		<div class="a-lil-toast-control">{{ message.content }}</div>
		<div class="a-lil-toast-control button" v-if="message.button">
			<a href="#" v-on:click="removeItem(id)">{{ (message.lang) ? closeText[message.lang] : closeText.en }}</a>
		</div>
	</div>
</div>
`
});

// -----

var app = new Vue({
	el: '#app',
	data: {
		messages: []
	},
	methods: {
		openToast(which) {
			// 'content', 'closed', 'type' is required
			this.messages.push({
				title: 'Hi! This is the title',
				content: 'This is the content, this is the content, this is the content',
				// To show/hide the 'close' button
				button: true,
				// HACK: Just the status of the toast if closed or something
				closed: '',
				// Color of the toast; possible values: 'default', 'primary', 'success', 'warning', and 'danger'.
				type: which,
				// Default language; Only available as of now is 'en', and 'ja'
				lang: 'en',
				// Timer (by milliseconds) when the toast will be closed. 0 if never
				timer: 0
			});
		}
	}
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js