Custom Templates
While the built-in templates cover many common scenarios, Astro Maintenance v2.0 also allows you to create fully custom maintenance pages. You have two main approaches for customization:
- Custom Handlebars Templates: Create your own template files with full control over HTML, CSS, and available variables (requires
?raw
imports in v2.0) - Internal Route Redirection: Redirect to a custom Astro page in your project
⚠️ Breaking Change in v2.0
Section titled “⚠️ Breaking Change in v2.0”Custom templates now require ?raw
imports for universal serverless compatibility. File path-based templates are no longer supported.
Custom Handlebars Templates
Section titled “Custom Handlebars Templates”You can create your own maintenance page template using Handlebars syntax. This gives you complete control over the appearance and functionality of your maintenance page.
Configuration
Section titled “Configuration”v2.0 Method (Current):
To use a custom template in v2.0, you must import the template content using ?raw
and pass it to the integration:
import { defineConfig } from "astro/config";import maintenance from "astro-maintenance";// Import template content using ?rawimport customTemplate from "./templates/custom-maintenance.hbs?raw";
export default defineConfig({ integrations: [ maintenance({ enabled: true, template: customTemplate, // Pass imported template content title: "Custom Maintenance Page", description: "Our site is getting an upgrade.", // ... other options will be passed to the template }), ],});
v1.x Method (Deprecated):
// ❌ This no longer works in v2.0maintenance({ template: "./templates/custom-maintenance.hbs", // File paths not supported});
Available Variables
Section titled “Available Variables”All configuration options you provide to the integration are available as variables in your Handlebars template. The most common ones include:
{{title}}
- The page title{{description}}
- The description text{{logo}}
- Path to the logo image, if provided{{emailAddress}}
- Contact email address, if provided{{emailText}}
- Text before the email address, if provided{{copyright}}
- Copyright text, if provided{{countdown}}
- ISO date string for countdown, if provided
Creating Your Custom Template File
Section titled “Creating Your Custom Template File”First, create your Handlebars template file (e.g., templates/custom-maintenance.hbs
):
<html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{{title}}</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background-color: #f5f5f5; color: #333; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } .container { max-width: 600px; padding: 40px; background-color: white; border-radius: 10px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); text-align: center; } img { max-width: 200px; margin-bottom: 20px; } h1 { margin-top: 0; color: #1e293b; } .description { margin-bottom: 30px; line-height: 1.6; } .contact { margin-top: 20px; font-size: 14px; color: #64748b; } footer { margin-top: 40px; font-size: 12px; color: #94a3b8; } </style> </head> <body> <div class="container"> {{#if logo}}<img src="{{logo}}" alt="Logo" />{{/if}} <h1>{{title}}</h1> <div class="description">{{description}}</div>
{{#if emailAddress}} <div class="contact"> {{emailText}} <a href="mailto:{{emailAddress}}">{{emailAddress}}</a> </div> {{/if}}
{{#if copyright}} <footer>{{copyright}}</footer> {{/if}} </div> </body></html>
Complete v2.0 Example
Section titled “Complete v2.0 Example”Here’s a complete example showing how to create and use a custom template in v2.0:
1. Create your template file (templates/custom-maintenance.hbs
):
<html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{{title}}</title> <style> /* Your custom styles */ body { font-family: system-ui, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; } .container { text-align: center; max-width: 600px; padding: 2rem; background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.2); } .logo { max-width: 150px; margin-bottom: 1rem; } h1 { font-size: 3rem; margin: 1rem 0; } p { font-size: 1.2rem; opacity: 0.9; } .contact { margin-top: 2rem; } .social-links { margin: 2rem 0; } .social-links a { margin: 0 0.5rem; color: white; text-decoration: none; opacity: 0.8; } .social-links a:hover { opacity: 1; } </style> </head> <body> <div class="container"> {{#if logo}}<img src="{{logo}}" alt="Logo" class="logo" />{{/if}} <h1>{{title}}</h1> <p>{{description}}</p>
{{#if socials}} <div class="social-links"> {{#if socials.twitter}}<a href="{{socials.twitter}}" target="_blank">Twitter</a>{{/if}} {{#if socials.github}}<a href="{{socials.github}}" target="_blank">GitHub</a>{{/if}} {{#if socials.linkedin}}<a href="{{socials.linkedin}}" target="_blank">LinkedIn</a>{{/if}} </div> {{/if}}
{{#if emailAddress}} <div class="contact"> {{emailText}} <a href="mailto:{{emailAddress}}" style="color: white;">{{emailAddress}}</a> </div> {{/if}}
{{#if copyright}} <footer style="margin-top: 2rem; opacity: 0.7; font-size: 0.9rem;">{{copyright}}</footer> {{/if}} </div> </body></html>
2. Import and use in your Astro config:
import { defineConfig } from "astro/config";import maintenance from "astro-maintenance";import customTemplate from "./templates/custom-maintenance.hbs?raw";
export default defineConfig({ integrations: [ maintenance({ enabled: true, template: customTemplate, title: "We'll Be Back Soon!", description: "Our website is getting a major upgrade with exciting new features.", logo: "/logo.png", emailText: "Questions? Contact us:", copyright: "© 2025 Your Company", socials: { twitter: "https://twitter.com/yourhandle", github: "https://github.com/yourusername", linkedin: "https://linkedin.com/in/yourprofile", }, override: "preview", }), ],});
Countdown Timer in Custom Templates
Section titled “Countdown Timer in Custom Templates”If you want to include a countdown timer in your custom template, you’ll need to add JavaScript to handle the countdown logic. Here’s a simplified example:
<html lang="en"> <!-- Head content here --> <body> <div class="container"> <!-- Other content here -->
{{#if countdown}} <div id="countdown"> <div id="days">00</div> days <div id="hours">00</div> hours <div id="minutes">00</div> minutes <div id="seconds">00</div> seconds </div>
<script> // Convert countdown string to Date object const countdownDate = new Date("{{countdown}}").getTime();
// Update the countdown every second const timer = setInterval(() => { const now = new Date().getTime(); const distance = countdownDate - now;
// Calculate days, hours, minutes, seconds const days = Math.floor(distance / (1000 * 60 * 60 * 24)); const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Display the result document.getElementById("days").textContent = days.toString().padStart(2, '0'); document.getElementById("hours").textContent = hours.toString().padStart(2, '0'); document.getElementById("minutes").textContent = minutes.toString().padStart(2, '0'); document.getElementById("seconds").textContent = seconds.toString().padStart(2, '0');
// If the countdown is finished, reload the page if (distance < 0) { clearInterval(timer); setTimeout(() => { window.location.reload(); }, 10000); // Try to reload every 10 seconds } }, 1000); </script> {{/if}} </div> </body></html>
Internal Route Redirection
Section titled “Internal Route Redirection”If you prefer to use Astro components for your maintenance page, you can redirect to a custom route in your Astro project:
maintenance({ enabled: true, template: "/custom-maintenance", // Redirects to this route in your Astro site override: "preview",})
This performs a 302 redirect to the specified route when maintenance mode is enabled. You’ll need to:
- Create a page at the specified route in your Astro project (e.g.,
/src/pages/custom-maintenance.astro
) - Build your maintenance page using Astro components, layouts, and styles
This approach lets you use all of Astro’s features for your maintenance page, including:
- Astro components
- Your site’s existing layouts
- CSS frameworks or styling solutions
- Client-side JavaScript when needed
Migration from v1.x
Section titled “Migration from v1.x”If you’re upgrading from v1.x, you need to update your custom template usage:
❌ v1.x (deprecated):
maintenance({ template: "./templates/custom.hbs", // File path - no longer works});
✅ v2.0 (required):
import customTemplate from "./templates/custom.hbs?raw";
maintenance({ template: customTemplate, // Imported content});
Best Practices for Custom Templates
Section titled “Best Practices for Custom Templates”When creating custom templates in v2.0:
- Import with
?raw
: Always use the?raw
suffix when importing template files - Keep it simple: Focus on clearly communicating maintenance status
- Make it responsive: Ensure your template works on all device sizes
- Include essential information: Always provide a title, description, and estimated completion time
- Branding: Include your logo and use your brand colors for consistency
- Contact information: Provide a way for users to get help during maintenance
- Universal compatibility: Your templates will work across all deployment platforms (Node.js, Cloudflare Workers, Vercel, Netlify)
- Testing: Test your custom template before deploying it to production
Next Steps
Section titled “Next Steps”Now that you’ve learned about all the available templates, check out these resources:
- Installation Guide - If you haven’t installed the integration yet
- Configuration Options - Learn about all available options
- GitHub Repository - View the source code and contribute