Appearance
Snackbar Component Code
Dependencies
This component requires:
- Vue 3 with Composition API
useSnackbarcomposableuuidpackage for unique ID generationconvertRemToPixelsinject (optional)
Full Component Code
vue
<script setup>
import { computed, inject } from 'vue';
import { useSnackbar } from '@/composables/useSnackbarComposable.js';
const convertRemToPixels = inject('convertRemToPixels', null);
const { notification, config, hasNotification, removeNotification } = useSnackbar();
// Handle close notification
const closeNotification = () => {
// You can add any additional logic here before removing
// For example: analytics, logging, etc.
removeNotification();
};
// Use individual notification position or fall back to global config
const notificationPosition = computed(() => {
return notification.value?.position || config.value.position;
});
const containerStyle = computed(() => {
let { x, y } = config.value.offset;
// Convert rem to pixels
x = convertRemToPixels ? convertRemToPixels(x) : x * parseInt(getComputedStyle(document.documentElement).fontSize);
y = convertRemToPixels ? convertRemToPixels(y) : y * parseInt(getComputedStyle(document.documentElement).fontSize);
// Use individual notification position or fall back to global config
const position = notification.value?.position || config.value.position;
const styles = {};
// Apply positioning based on notification position
switch (position) {
case 'top-right':
styles.top = `${y}px`;
styles.right = `${x}px`;
break;
case 'top-left':
styles.top = `${y}px`;
styles.left = `${x}px`;
break;
case 'top':
styles.top = `${y}px`;
styles.left = '50%';
styles.transform = 'translateX(-50%)';
break;
case 'bottom-right':
styles.bottom = `${y}px`;
styles.right = `${x}px`;
break;
case 'bottom-left':
styles.bottom = `${y}px`;
styles.left = `${x}px`;
break;
case 'bottom':
styles.bottom = `${y}px`;
styles.left = '50%';
styles.transform = 'translateX(-50%)';
break;
}
return styles;
});
</script>
<template>
<div v-if="notification" :class="['snackbar-container', `position-${notificationPosition}`]" :style="containerStyle">
<div :class="['snackbar-notification', ...notification.notificationClass]">
<div class="snackbar-content">
<div class="snackbar-icon" v-if="notification.iconRef" v-html="notification.iconRef"></div>
<div class="snackbar-messages">
<div class="snackbar-primary-message">{{ notification.primaryMessage }}</div>
<div v-if="notification.secondaryMessage" class="snackbar-secondary-message">
{{ notification.secondaryMessage }}
</div>
</div>
<button
v-if="notification.showCloseButton"
@click="closeNotification"
class="snackbar-close-button"
aria-label="Close notification"
>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.5 3.5L3.5 10.5M3.5 3.5L10.5 10.5"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.snackbar-container {
position: fixed;
z-index: 9999;
background: transparent;
}
.snackbar-notification {
min-width: 18.75rem;
max-width: 25rem;
background: white;
border-radius: 8px;
border: 1px solid #e5e7eb;
overflow: hidden;
.snackbar-content {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
gap: 0.75rem;
}
.snackbar-icon {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
margin-top: 0.125rem;
}
.snackbar-messages {
flex: 1;
min-width: 0;
}
.snackbar-primary-message {
font-size: 0.875rem;
font-weight: 500;
color: #111827;
margin: 0;
line-height: 1.4;
}
.snackbar-secondary-message {
font-size: 0.8125rem;
color: #6b7280;
margin: 0.25rem 0 0 0;
line-height: 1.4;
}
.snackbar-close-button {
flex-shrink: 0;
background: none;
border: none;
cursor: pointer;
padding: 0.25rem;
border-radius: 0.25rem;
color: #9ca3af;
transition: all 0.2s ease;
&:hover {
color: #6b7280;
background-color: #f3f4f6;
}
}
// Type-specific styling
&.success {
border-left: 4px solid #10b981;
.snackbar-content {
.snackbar-primary-message {
color: #10b981;
}
}
}
&.error {
border-left: 4px solid #ef4444;
.snackbar-content {
.snackbar-primary-message {
color: #ef4444;
}
}
}
&.warning {
border-left: 4px solid #f59e0b;
.snackbar-content {
.snackbar-primary-message {
color: #f59e0b;
}
}
}
&.info {
border-left: 4px solid #3b82f6;
.snackbar-content {
.snackbar-primary-message {
color: #3b82f6;
}
}
}
}
</style>