Templates let you build completely custom social card layouts. Instead of styling your existing page, you define a new layout that extracts content from your page using JavaScript expressions.
How templates work
Add a <template> element with the id ogplus to your page:
<template id="ogplus">
<div style="padding: 48px; background: #1a1a2e; color: white; height: 100%;">
<h1 style="font-size: 48px; margin: 0;">
${document.querySelector('h1')?.textContent}
</h1>
<p style="font-size: 24px; color: #888; margin-top: 16px;">
${document.querySelector('meta[name="description"]')?.content}
</p>
</div>
</template>
When OpenGraph+ renders your page, it:
- Finds the
<template id="ogplus">element - Evaluates any
${...}expressions against your page’s DOM - Replaces the page body with the rendered template
- Captures the result as your social card image
The template content is invisible to regular visitors—<template> elements don’t render in the browser.
Template expressions
Use ${...} to insert dynamic content. Any valid JavaScript expression works:
<template id="ogplus">
<!-- Text content -->
<h1>${document.querySelector('h1')?.textContent}</h1>
<!-- Attribute values -->
<img src="${document.querySelector('.hero img')?.src}">
<!-- Meta tags -->
<p>${document.querySelector('meta[property="og:description"]')?.content}</p>
<!-- Computed values -->
<span>${new Date().toLocaleDateString()}</span>
<!-- Conditional content -->
<span>${document.querySelector('.author')?.textContent || 'Anonymous'}</span>
</template>
Use optional chaining (?.) to safely handle missing elements without errors.
Platform-specific templates
Create different layouts for different social platforms using ogplus-{platform} ids:
<!-- Twitter-specific template -->
<template id="ogplus-twitter">
<div style="background: #15202b; color: white; padding: 40px;">
<h1>${document.querySelector('h1')?.textContent}</h1>
</div>
</template>
<!-- LinkedIn-specific template -->
<template id="ogplus-linkedin">
<div style="background: #0077b5; color: white; padding: 60px;">
<h1>${document.querySelector('h1')?.textContent}</h1>
</div>
</template>
<!-- Fallback for other platforms -->
<template id="ogplus">
<div style="background: white; padding: 40px;">
<h1>${document.querySelector('h1')?.textContent}</h1>
</div>
</template>
OpenGraph+ checks for templates in this order:
template#ogplus-{platform}(e.g.,template#ogplus-twitter)template#ogplus(generic fallback)
If no template is found, OpenGraph+ falls back to rendering your page normally (with CSS styling via data-ogplus).
Inline styles
Templates render in isolation—your page’s stylesheets don’t apply. Use inline styles for all formatting:
<template id="ogplus">
<div style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-family: system-ui, sans-serif;
">
<h1 style="font-size: 64px; margin: 0; text-align: center;">
${document.querySelector('h1')?.textContent}
</h1>
</div>
</template>
Full viewport layout
Your template fills the entire social card viewport. Use height: 100% on your root element to take up the full space:
<template id="ogplus">
<div style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background: #f5f5f0;
">
<!-- Your content -->
</div>
</template>
Grabbing existing elements
Instead of rebuilding your layout from scratch, you can grab and restyle existing elements from your page:
<template id="ogplus">
<div style="padding: 40px; background: white; height: 100%;">
${document.querySelector('.article-header')?.outerHTML}
</div>
</template>
This clones the .article-header element with all its children. Note that styles may not carry over if they depend on parent selectors or external stylesheets.
Example: Blog post card
A complete example for blog posts:
<template id="ogplus">
<div style="
display: flex;
flex-direction: column;
padding: 48px;
background: #0f172a;
color: white;
font-family: system-ui, sans-serif;
height: 100%;
box-sizing: border-box;
">
<div style="
font-size: 14px;
text-transform: uppercase;
letter-spacing: 2px;
color: #94a3b8;
margin-bottom: 24px;
">
${document.querySelector('.category')?.textContent || 'Blog'}
</div>
<h1 style="
font-size: 56px;
font-weight: bold;
line-height: 1.1;
margin: 0 0 24px 0;
flex: 1;
">
${document.querySelector('h1')?.textContent}
</h1>
<div style="
display: flex;
align-items: center;
gap: 16px;
font-size: 18px;
color: #94a3b8;
">
<img
src="${document.querySelector('.author-avatar')?.src}"
style="width: 48px; height: 48px; border-radius: 50%;"
>
<span>${document.querySelector('.author-name')?.textContent}</span>
<span>·</span>
<span>${document.querySelector('.publish-date')?.textContent}</span>
</div>
</div>
</template>
Example: Product card
For e-commerce or product pages:
<template id="ogplus">
<div style="
display: flex;
height: 100%;
background: white;
font-family: system-ui, sans-serif;
">
<img
src="${document.querySelector('.product-image')?.src}"
style="width: 50%; height: 100%; object-fit: cover;"
>
<div style="
flex: 1;
padding: 48px;
display: flex;
flex-direction: column;
justify-content: center;
">
<h1 style="font-size: 36px; margin: 0 0 16px 0;">
${document.querySelector('.product-name')?.textContent}
</h1>
<p style="font-size: 24px; color: #16a34a; font-weight: bold; margin: 0;">
${document.querySelector('.product-price')?.textContent}
</p>
</div>
</div>
</template>
Combining with meta tags
Templates work alongside other OpenGraph+ meta tags:
<head>
<!-- Set viewport width for template rendering -->
<meta property="og:plus:viewport:width" content="800">
<!-- Add extra styles to the body -->
<meta property="og:plus:style" content="margin: 0; padding: 0;">
</head>
<body>
<template id="ogplus">
<!-- Your template -->
</template>
</body>
Templates vs CSS styling
| Feature | CSS Styling | Templates |
|---|---|---|
| Complexity | Simple show/hide | Full custom layouts |
| Styles | Uses your existing CSS | Inline styles only |
| Layout | Adapts your page | Completely custom |
| Content | Shows/hides existing elements | Extracts and rearranges content |
| Best for | Minor adjustments | Branded social cards |
Use CSS styling when you just need to hide navigation and adjust spacing. Use templates when you want a completely different layout for social cards.