How to Create a Custom Snippet in Odoo Website
Step-by-step guide to building reusable drag-and-drop building blocks for the Odoo Website editor — from XML template to live snippet panel. Verified for Odoo 18 & 19.
Odoo Website's drag-and-drop editor is built on reusable building blocks called snippets. Every block you see in the editor panel — from hero banners to testimonial carousels — is a snippet registered via an XML view that inherits from the main snippet list. Creating your own snippet follows the same pattern: write an HTML template, register it in the editor panel, and optionally attach CSS and JavaScript options. This guide covers the complete workflow for Odoo 18 and 19.
What Is an Odoo Snippet?
A snippet (also called a building block) is a self-contained HTML section that website editors can drag from the panel onto any page. Snippets consist of three parts: an HTML template (the visual block), a snippet registration view (which makes it appear in the editor panel), and optional snippet options (JavaScript classes that add editor controls like colour pickers or layout toggles).
| Component | File location | Required | Purpose |
|---|---|---|---|
| HTML template | views/snippets/s_my_snippet.xml | Yes | The visual block dropped onto the page |
| Registration view | views/snippets/snippets.xml | Yes | Adds the block to the editor panel under a category |
| Snippet options JS | static/src/js/options.js | No | Editor controls (layout, colour, visibility toggles) |
| CSS styles | static/src/scss/s_my_snippet.scss | No | Scoped styles for the snippet block |
| __manifest__.py entry | Module root | Yes | Declares XML + JS + CSS assets to Odoo's asset pipeline |
Module Structure
Custom snippets must live inside an Odoo module. If you are adding a snippet to an existing website module, skip the scaffold step. For a new module, the minimum directory layout is:
my_website_snippets/
├── __init__.py
├── __manifest__.py
├── static/
│ └── src/
│ ├── js/
│ │ └── options.js # snippet options (optional)
│ └── scss/
│ └── s_my_snippet.scss # snippet styles (optional)
└── views/
└── snippets/
├── s_my_snippet.xml # HTML template
└── snippets.xml # editor panel registrationStep 1 — Write the HTML Template
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="s_my_cta_banner" name="My CTA Banner">
<section class="s_my_cta_banner" data-snippet="s_my_cta_banner"
data-name="My CTA Banner">
<div class="container text-center py-5">
<h2 class="s_my_cta_banner_title">Your headline goes here</h2>
<p class="lead s_my_cta_banner_subtitle">
Supporting text for your call to action.
</p>
<a href="#" class="btn btn-primary btn-lg">Get Started</a>
</div>
</section>
</template>
</odoo>Key points: the root element must be ``. The `data-snippet` attribute must match the template `id`. The `data-name` attribute sets the tooltip shown in the editor when the user hovers over the dropped block.
Step 2 — Register the Snippet in the Editor Panel
The editor panel is controlled by the view `website.snippets`. You extend it using an XPath to inject your snippet thumbnail into one of the panel categories: Content, Structure, Inner Content, or Features.
| Category | XPath target | Typical use |
|---|---|---|
| Content | //div[@id="snippet_content"] | Hero banners, text blocks, media |
| Structure | //div[@id="snippet_structure"] | Columns, cards, layouts |
| Features | //div[@id="snippet_feature"] | Counters, tabs, accordions |
| Inner Content | //div[@id="snippet_innerContent"] | Elements placed inside other snippets |
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Register snippet in the "Content" panel category -->
<template id="snippets" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_content']" position="before">
<t t-snippet="my_website_snippets.s_my_cta_banner"
t-thumbnail="/my_website_snippets/static/src/img/thumb_my_cta_banner.png"/>
</xpath>
</template>
</odoo>Step 3 — Declare Files in __manifest__.py
{
'name': 'My Website Snippets',
'version': '1.0',
'category': 'Website',
'depends': ['website'],
'data': [
'views/snippets/s_my_snippet.xml',
'views/snippets/snippets.xml',
],
'assets': {
'web.assets_frontend': [
'my_website_snippets/static/src/scss/s_my_snippet.scss',
'my_website_snippets/static/src/js/options.js',
],
},
'installable': True,
}Step 4 — Add Snippet Options (Optional)
Snippet options are JavaScript classes that extend `SnippetOptionWidget` (or one of its sub-classes). They add editor panel controls — colour pickers, layout toggles, text inputs — that appear when the user clicks your snippet in the editor. Options are bound to the snippet's root CSS selector.
/** @odoo-module **/
import options from "@web_editor/js/editor/snippets.options";
options.registry.MyCTABanner = options.Class.extend({
// Called when the user changes an option value
setBannerStyle: function (previewMode, value) {
this.$target.toggleClass("s_my_cta_banner_dark", value === "dark");
this.$target.toggleClass("s_my_cta_banner_light", value === "light");
},
});The registry key (`MyCTABanner`) must match the `data-js` attribute you add to your registration `` element, or Odoo uses the CSS class name of the snippet's root element as a fallback key.
Step 5 — Install the Module and Test
- Restart the Odoo server to pick up the new module: `./odoo-bin -c odoo.conf -u my_website_snippets`.
- Open the Website app and click **Edit** on any page.
- In the building blocks panel, locate your snippet under the category you registered it in (e.g. Content).
- Drag the snippet onto the page and confirm it renders correctly.
- Click the dropped block to open the editor panel and verify any custom options appear.
- Save the page and reload in normal (non-edit) mode to confirm the snippet displays without editor scripts.
Troubleshooting — Common Issues
| Symptom | Likely cause | Fix |
|---|---|---|
| Snippet not visible in editor panel | XML not declared in __manifest__.py `data` list, or module not updated | Add the XML file to `data`, then run `-u my_module`. Clear browser cache. |
| Snippet appears but renders blank | Template ID mismatch between s_my_snippet.xml and the `t-snippet` reference | Verify `t-snippet='module_name.template_id'` matches exactly, including the module prefix. |
| CSS styles not applied | SCSS file not in `web.assets_frontend` or Odoo assets not re-generated | Add SCSS path to manifest assets, restart server with `-u`, clear cache with `?debug=assets`. |
| Snippet options panel empty / JS not running | Options JS not bundled in the correct asset (must be in `web.assets_backend` for editor mode) | Add options.js to both `web.assets_frontend` and `web.assets_backend` in manifest. |
| `data-snippet` warning in browser console | `data-snippet` value does not match the template ID on the root `<section>` | Set `data-snippet='s_my_cta_banner'` on the root tag to match the template `id` exactly. |
Version Notes
| Odoo version | Key change affecting snippets |
|---|---|
| Odoo 15 | Legacy asset bundle: `website.assets_frontend`. Editor options use `options.Class.extend()`. |
| Odoo 16 | Asset bundle renamed to `web.assets_frontend`. OWL 2 introduced — but snippet options still use legacy JS class system. |
| Odoo 17 | `@odoo-module` ESM syntax required for new JS files. `data-snippet` attribute enforced — console warning if missing. |
| Odoo 18 | Snippet panel UI redesigned — category order may differ. `t-thumbnail` path convention unchanged. Options JS API stable. |
| Odoo 19 | No breaking changes to snippet registration or options API. `web.assets_frontend` bundle remains canonical. |
Need Custom Website Building Blocks for Your Odoo Site?
Our Odoo-certified developers build custom snippets, website themes, and full e-commerce integrations tailored to Saudi business requirements.
Frequently Asked Questions
What is the difference between a snippet and a widget in Odoo Website?
Can I add a custom snippet without creating a new Odoo module?
How do I make a snippet available only on specific pages?
My snippet was saved on a page but disappeared after a module update. Why?
Can I use Odoo Studio to create a snippet?
How do I make snippet text editable by website editors?

iWesabe Editorial Team
Practitioner insights on Odoo ERP, ZATCA compliance, and Saudi enterprise digital operations — written by iWesabe's consulting, finance, and engineering teams.
Related Articles
How to Configure Email in Odoo
A complete guide to setting up outgoing and incoming mail servers in Odoo — covering SMTP, Gmail, Microsoft 365, catch-all aliases, and email deliverability best practices.
Custom Paper Format in Odoo QWeb Reports
How to create, configure, and bind custom paper formats to Odoo QWeb reports — covering UI setup, XML override, margin control, and header/footer sizing.
Odoo attrs Deprecated: Migrating to invisible, readonly, and required in Odoo 16–19
The attrs dictionary was deprecated in Odoo 16 and removed in Odoo 17. This guide maps every attrs pattern to its direct-attribute replacement — with before/after code for the most common use cases. Verified for Odoo 18 & 19.
Explore Related Solutions
Shopify Integration for Odoo
Shopify sends orders, refunds, customers, and product updates to Odoo Sales, Inventory, and Accounting in real time — Odoo sends the product catalogue, stock by location, pricing, and fulfilment status back to Shopify — and every online order generates a ZATCA Phase-2 compliant e-invoice inside Odoo automatically.
ExploreSalla Integration for Odoo
Connect your Salla store to Odoo so every online order, customer, and stock movement flows straight into your back office. Orders become Odoo sales orders with ZATCA-aligned invoices, inventory syncs both ways to stop overselling, and fulfilment status flows back to Salla — one operation across storefront and ERP, with no manual re-entry.
ExploreWooCommerce Integration for Odoo
WooCommerce sends orders, customers, payments, and refunds to Odoo Sales, Inventory, and Accounting in real time — Odoo sends the product catalogue, stock levels, pricing, and fulfilment status back to your WordPress store — and every online order generates a ZATCA Phase-2 compliant e-invoice inside Odoo automatically.
ExploreCRM & Customer Relationship Management
Turn every lead into a closed deal. Odoo CRM gives your sales team a structured Kanban pipeline, automated follow-up sequences, and a 360° customer view — all connected natively to Accounting, Inventory, and Email Marketing.
Explore