Skip to main content
Vue Print It provides event callbacks to hook into the print lifecycle, allowing you to run code before printing starts, after it completes, or when errors occur.

Available callbacks

Three callback functions are available:
  • onBeforePrint - Called before the print dialog opens
  • onAfterPrint - Called after printing completes or is cancelled
  • onPrintError - Called if an error occurs during printing

onBeforePrint

Execute code before printing starts:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const lastPrintTime = ref(null)

function handlePrint() {
  print('content', {
    onBeforePrint: () => {
      console.log('Preparing to print...')
      lastPrintTime.value = new Date()
    }
  })
}
</script>

Async onBeforePrint

The callback can be async:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const userData = ref(null)

async function handlePrint() {
  await print('invoice', {
    onBeforePrint: async () => {
      // Fetch additional data before printing
      const response = await fetch('/api/user')
      userData.value = await response.json()
      
      // Update the DOM before print
      await new Promise(resolve => setTimeout(resolve, 100))
    }
  })
}
</script>

onAfterPrint

Execute code after printing completes:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const printCount = ref(0)

function handlePrint() {
  print('content', {
    onAfterPrint: () => {
      console.log('Print completed or cancelled')
      printCount.value++
      
      // Track print analytics
      analytics.track('document_printed', {
        timestamp: new Date().toISOString()
      })
    }
  })
}
</script>
onAfterPrint is called whether the user completes the print or cancels it.

onPrintError

Handle errors that occur during printing:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const errorMessage = ref('')

function handlePrint() {
  print('content', {
    onPrintError: (error: Error) => {
      console.error('Print error:', error)
      errorMessage.value = `Failed to print: ${error.message}`
      
      // Show user-friendly error message
      alert('Unable to print. Please try again.')
    }
  })
}
</script>

<template>
  <div>
    <button @click="handlePrint">Print</button>
    <p v-if="errorMessage" class="error">{{ errorMessage }}</p>
  </div>
</template>

Loading states

Show loading indicators during printing:
<template>
  <div>
    <div id="content">
      <h1>Document</h1>
      <p>Content to print</p>
    </div>
    
    <button 
      @click="handlePrint" 
      :disabled="isPrinting"
      :class="{ 'loading': isPrinting }"
    >
      {{ isPrinting ? 'Printing...' : 'Print' }}
    </button>
    
    <div v-if="isPrinting" class="loading-overlay">
      <div class="spinner"></div>
      <p>Preparing document...</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const isPrinting = ref(false)

async function handlePrint() {
  isPrinting.value = true
  
  try {
    await print('content', {
      onBeforePrint: () => {
        console.log('Opening print dialog...')
      },
      onAfterPrint: () => {
        console.log('Print dialog closed')
      },
      onPrintError: (error) => {
        console.error('Print failed:', error)
      }
    })
  } finally {
    isPrinting.value = false
  }
}
</script>

<style>
.loading {
  opacity: 0.6;
  cursor: wait;
}

.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: white;
}

.spinner {
  border: 4px solid rgba(255, 255, 255, 0.3);
  border-top-color: white;
  border-radius: 50%;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}
</style>

Status tracking

Track the print status:
<template>
  <div>
    <div id="content">
      <h1>Document</h1>
    </div>
    
    <button @click="handlePrint">Print</button>
    
    <div class="status">
      <p>Status: {{ status }}</p>
      <p v-if="lastPrintTime">
        Last printed: {{ lastPrintTime.toLocaleString() }}
      </p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const status = ref('Ready')
const lastPrintTime = ref<Date | null>(null)

async function handlePrint() {
  status.value = 'Preparing...'
  
  try {
    await print('content', {
      onBeforePrint: () => {
        status.value = 'Printing...'
      },
      onAfterPrint: () => {
        status.value = 'Completed'
        lastPrintTime.value = new Date()
        
        // Reset status after 3 seconds
        setTimeout(() => {
          status.value = 'Ready'
        }, 3000)
      },
      onPrintError: (error) => {
        status.value = `Error: ${error.message}`
      }
    })
  } catch (error) {
    status.value = 'Failed'
  }
}
</script>

Analytics tracking

Track print events in your analytics:
<script setup>
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

function handlePrint() {
  const startTime = Date.now()
  
  print('content', {
    onBeforePrint: () => {
      // Track print initiation
      analytics.track('print_started', {
        documentType: 'invoice',
        documentId: 'INV-12345',
        timestamp: new Date().toISOString()
      })
    },
    onAfterPrint: () => {
      const duration = Date.now() - startTime
      
      // Track print completion
      analytics.track('print_completed', {
        documentType: 'invoice',
        documentId: 'INV-12345',
        duration,
        timestamp: new Date().toISOString()
      })
    },
    onPrintError: (error) => {
      // Track print errors
      analytics.track('print_error', {
        documentType: 'invoice',
        documentId: 'INV-12345',
        error: error.message,
        timestamp: new Date().toISOString()
      })
    }
  })
}
</script>

Combining with other features

Use callbacks with custom styles and options:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const printHistory = ref([])

function handlePrint() {
  const printJob = {
    id: Date.now(),
    status: 'pending',
    timestamp: new Date()
  }
  
  printHistory.value.push(printJob)
  
  print('invoice', {
    windowTitle: 'Invoice #12345',
    preserveStyles: true,
    timeout: 1500,
    styles: [
      '@page { margin: 1in; }',
      'body { font-family: Arial, sans-serif; }'
    ],
    onBeforePrint: async () => {
      printJob.status = 'printing'
      
      // Fetch latest data
      const response = await fetch('/api/invoice/12345')
      const data = await response.json()
      
      // Update DOM
      document.getElementById('invoice-data').textContent = 
        JSON.stringify(data)
    },
    onAfterPrint: () => {
      printJob.status = 'completed'
    },
    onPrintError: (error) => {
      printJob.status = 'failed'
      printJob.error = error.message
    }
  })
}
</script>

Complete example

A comprehensive example combining all callbacks:
<template>
  <div class="print-manager">
    <div id="document">
      <h1>{{ documentTitle }}</h1>
      <p>{{ documentContent }}</p>
      <p v-if="additionalData">
        Generated at: {{ additionalData.generatedAt }}
      </p>
    </div>
    
    <div class="controls">
      <button 
        @click="handlePrint" 
        :disabled="isPrinting"
      >
        {{ isPrinting ? 'Printing...' : 'Print Document' }}
      </button>
      
      <div v-if="status" class="status" :class="statusClass">
        {{ status }}
      </div>
    </div>
    
    <div v-if="printHistory.length" class="history">
      <h3>Print History</h3>
      <ul>
        <li v-for="entry in printHistory" :key="entry.timestamp">
          {{ entry.timestamp.toLocaleTimeString() }} - 
          {{ entry.status }}
          <span v-if="entry.error"> ({{ entry.error }})</span>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

const documentTitle = ref('Important Document')
const documentContent = ref('This is the document content.')
const additionalData = ref(null)
const isPrinting = ref(false)
const status = ref('')
const printHistory = ref([])

const statusClass = computed(() => ({
  'status-printing': status.value === 'Printing...',
  'status-success': status.value === 'Print completed!',
  'status-error': status.value.startsWith('Error')
}))

async function handlePrint() {
  isPrinting.value = true
  status.value = 'Preparing...'
  
  const historyEntry = {
    timestamp: new Date(),
    status: 'started',
    error: null
  }
  
  try {
    await print('document', {
      windowTitle: documentTitle.value,
      preserveStyles: true,
      
      onBeforePrint: async () => {
        status.value = 'Printing...'
        
        // Fetch additional data
        try {
          const response = await fetch('/api/document-metadata')
          additionalData.value = await response.json()
        } catch (error) {
          console.warn('Could not fetch metadata:', error)
        }
        
        // Wait for DOM update
        await new Promise(resolve => setTimeout(resolve, 100))
      },
      
      onAfterPrint: () => {
        status.value = 'Print completed!'
        historyEntry.status = 'completed'
        
        // Clear status after 3 seconds
        setTimeout(() => {
          status.value = ''
        }, 3000)
      },
      
      onPrintError: (error: Error) => {
        status.value = `Error: ${error.message}`
        historyEntry.status = 'failed'
        historyEntry.error = error.message
        
        console.error('Print error:', error)
      }
    })
  } finally {
    isPrinting.value = false
    printHistory.value.unshift(historyEntry)
    
    // Keep only last 10 entries
    if (printHistory.value.length > 10) {
      printHistory.value = printHistory.value.slice(0, 10)
    }
  }
}
</script>

<style scoped>
.print-manager {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

#document {
  border: 1px solid #ccc;
  padding: 20px;
  margin-bottom: 20px;
}

.controls {
  display: flex;
  gap: 10px;
  align-items: center;
}

button {
  padding: 10px 20px;
  font-size: 16px;
}

button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.status {
  padding: 8px 12px;
  border-radius: 4px;
}

.status-printing {
  background: #fef3c7;
  color: #92400e;
}

.status-success {
  background: #d1fae5;
  color: #065f46;
}

.status-error {
  background: #fee2e2;
  color: #991b1b;
}

.history {
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid #ccc;
}

.history ul {
  list-style: none;
  padding: 0;
}

.history li {
  padding: 5px 0;
  font-size: 14px;
  color: #666;
}
</style>

Next steps

Error handling

Learn comprehensive error handling

Custom styles

Customize print layouts

Configuration

View all configuration options

API Reference

Complete PrintOptions reference

Build docs developers (and LLMs) love