Handleiding: Prijs Exclusief BTW Block voor Shopify

Handleiding: Prijs Exclusief BTW Block voor Shopify

Het duidelijk tonen van prijzen exclusief BTW is essentieel voor B2B webshops. In deze handleiding leg ik stap voor stap uit hoe je eenvoudig een Shopify block toevoegt.

Shopify code tutorial
Jul 17, 2025

Waarom deze oplossing?

Ken je dat gevoel? Je hebt een mooie Shopify-winkel, verkoopt aan zowel particulieren als bedrijven, en dan krijg je steeds weer die ene vraag: "Ja, maar hoeveel is het zonder BTW?"

Het wordt nog vervelender als je bedenkt dat zakelijke klanten vaak hun beslissingen baseren op netto prijzen. Ze moeten budgetten verantwoorden, offertes maken, en willen gewoon direct zien wat ze kwijt zijn exclusief BTW. En laten we eerlijk zijn - het handmatig uitrekenen en mailen kost gewoon te veel tijd.

Daarom heb ik deze handige oplossing gebouwd. Het is een block dat automatisch de prijs zonder BTW toont, direct onder je normale prijs. Het werkt met alle moderne Shopify-thema's en het mooiste is: als iemand een andere variant kiest (andere kleur, maat, whatever), past de BTW-prijs zich meteen aan. Geen gedoe, gewoon werkend.

Wat kan dit block allemaal?

Voordat we gaan klooien met code, even snel wat je ermee kunt. Het rekent natuurlijk automatisch je BTW uit (je stelt zelf het percentage in). Maar het kan meer. Je kunt er een mooi "Zakelijk" labeltje bij zetten, de kleuren aanpassen zodat het perfect bij je huisstijl past, en zelfs kiezen hoe je prijsbereiken wilt tonen.

Oh, en het werkt gewoon goed op telefoons. Dat is tegenwoordig geen luxe meer, maar noodzaak.

Laten we beginnen met installeren

Stap 1: De snippet maken

Oké, eerst even inloggen in je Shopify-admin. Ga naar Online Store > Themes. Bij je actieve thema zie je een knopje Actions, klik daarop en kies Edit code.

Nu zie je een hoop mappen aan de linkerkant. Zoek de map Snippets op en klik op Add a new snippet. Geef het de naam price-ex-btw (zonder aanhalingstekens) en klik op Create snippet.

Goed, nu komt het echte werk. Delete alles wat er staat en plak deze code:

liquid

{% comment %}  ⚡️ Prijs Exclusief BTW Snippet by Diek Thunnissen

 - Werkt met echte product variants (variant-selects component)
 - Werkt met product variations (verschillende producten)
 - Detecteert beide systemen automatisch
{% endcomment %}
{%- liquid
 # Bereken prijzen excl. BTW
 assign btw_percentage = block.settings.btw_percentage | times: 1.0 | divided_by: 100.0
 assign btw_multiplier = 1.0 | plus: btw_percentage

 # Bereken de afrondfactor
 assign decimal_places = block.settings.decimal_places | default: 2
 assign rounding_factor = decimal_places | prepend: '1' | append: '0' | times: 1

 # Voor product variations gebruiken we altijd het huidige product
 assign target_product = product

 # Verwerk prijzen voor het huidige product
 if product.price_varies
   assign regular_price_min = product.price_min | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
   assign regular_price_max = product.price_max | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
 else
   assign regular_price = product.price | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
 endif

 # Als er een selected variant is, gebruik die prijs
 if product.selected_or_first_available_variant
   assign variant_price = product.selected_or_first_available_variant.price | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
 endif
-%}

<style>
 .zakelijk-btw-container {
   display: flex;
   align-items: center;
   gap: 8px;
   margin-top: {{ block.settings.spacing | default: 8 }}px;
   margin-bottom: 12px;
 }

 .zakelijk-tag {
   display: inline-block;
   background-color: {{ block.settings.badge_bg_color | default: '#a18367' }};
   color: {{ block.settings.badge_text_color | default: '#ffffff' }};
   font-size: 12px;
   padding: 3px 10px;
   border-radius: {{ block.settings.badge_radius | default: 3 }}px;
 }

 .ex-btw-price {
   font-size: {{ block.settings.font_size | default: 14 }}px;
   color: {{ block.settings.price_color | default: '#000000' }};
   font-weight: {{ block.settings.price_weight | default: 'bold' }};
 }

 .ex-btw-label {
   color: {{ block.settings.label_color | default: '#707070' }};
   font-weight: {{ block.settings.label_weight | default: 'normal' }};
   font-size: {{ block.settings.font_size | default: 14 }}px;
   {% if block.settings.label_style == 'italic' %}font-style: italic;{% endif %}
 }

 {% if block.settings.custom_css != blank %}
   {{ block.settings.custom_css }}
 {% endif %}
</style>

<div class="zakelijk-btw-container {{ block.settings.custom_class }}" id="btw-price-container">
 {% if block.settings.show_badge %}
   <span class="zakelijk-tag">{{ block.settings.badge_text | default: 'Zakelijk' }}</span>
 {% endif %}

 <span class="ex-btw-label">{{ block.settings.label_text | default: 'Excl. BTW:' }}</span>

 {%- if product.price_varies -%}
   <span class="ex-btw-price" id="btw-price-display">
     {%- if block.settings.price_format == 'from' -%}
       {{ block.settings.from_text | default: 'Vanaf' }} {{ regular_price_min | money }}
     {%- else -%}
       {{ regular_price_min | money }}{{ block.settings.range_separator | default: ' - ' }}{{ regular_price_max | money }}
     {%- endif -%}
   </span>
 {%- else -%}
   <span class="ex-btw-price" id="btw-price-display">
     {%- if variant_price -%}
       {{ variant_price | money }}
     {%- else -%}
       {{ regular_price | money }}
     {%- endif -%}
   </span>
 {%- endif -%}

 {% if block.settings.show_inc_btw %}
   {% if block.settings.inc_btw_placement == 'inline' %}
     <span class="ex-btw-label" style="margin-left: 8px;">{{ block.settings.inc_btw_label | default: 'Incl. BTW:' }}</span>
     <span class="ex-btw-price" id="inc-btw-price-display">
       {%- if product.price_varies -%}
         {%- if block.settings.price_format == 'from' -%}
           {{ block.settings.from_text | default: 'Vanaf' }} {{ product.price_min | money }}
         {%- else -%}
           {{ product.price_min | money }}{{ block.settings.range_separator | default: ' - ' }}{{ product.price_max | money }}
         {%- endif -%}
       {%- else -%}
         {%- if product.selected_or_first_available_variant -%}
           {{ product.selected_or_first_available_variant.price | money }}
         {%- else -%}
           {{ product.price | money }}
         {%- endif -%}
       {%- endif -%}
     </span>
   {% endif %}
 {% endif %}
</div>

{% if block.settings.show_inc_btw and block.settings.inc_btw_placement == 'under' %}
 <div class="zakelijk-btw-container {{ block.settings.custom_class }}" style="margin-top: 4px;">
   <span class="ex-btw-label">{{ block.settings.inc_btw_label | default: 'Incl. BTW:' }}</span>
   <span class="ex-btw-price" id="inc-btw-price-display-under">
     {%- if product.price_varies -%}
       {%- if block.settings.price_format == 'from' -%}
         {{ block.settings.from_text | default: 'Vanaf' }} {{ product.price_min | money }}
       {%- else -%}
         {{ product.price_min | money }}{{ block.settings.range_separator | default: ' - ' }}{{ product.price_max | money }}
       {%- endif -%}
     {%- else -%}
       {%- if product.selected_or_first_available_variant -%}
         {{ product.selected_or_first_available_variant.price | money }}
       {%- else -%}
         {{ product.price | money }}
       {%- endif -%}
     {%- endif -%}
   </span>
 </div>
{% endif %}

{% comment %}
JavaScript voor variant price updates{% endcomment %}
{% if template == 'product' %}
<script>
document.addEventListener('DOMContentLoaded', function() {
 const BTW_MULTIPLIER = {{ btw_multiplier }};
 const btwPriceDisplay = document.getElementById('btw-price-display');
 const incBtwPriceDisplay = document.getElementById('inc-btw-price-display');
 const incBtwPriceDisplayUnder = document.getElementById('inc-btw-price-display-under');

 if (!btwPriceDisplay) return;

 
// Functie om BTW prijzen te updaten
 function updateBTWPrices(variantId) {
   if (!variantId) return;

   
// Zoek variant data uit het JSON script in variant-selects
   const variantScript = document.querySelector('variant-selects script[data-selected-variant]');
   let variantData = null;

   if (variantScript) {
     try {
       const selectedVariant = JSON.parse(variantScript.textContent);
       if (selectedVariant && selectedVariant.id.toString() === variantId.toString()) {
         variantData = selectedVariant;
       }
     } catch (e) {
       console.log('Error parsing selected variant:', e);
     }
   }

   
// Als geen data van script, zoek alle variants
   if (!variantData) {
     
// Zoek in window object
     if (window.productData && window.productData.variants) {
       variantData = window.productData.variants.find(v => v.id.toString() === variantId.toString());
     }

     
// Zoek in andere mogelijke locaties
     if (!variantData && window.product && window.product.variants) {
       variantData = window.product.variants.find(v => v.id.toString() === variantId.toString());
     }
   }

   if (variantData && variantData.price) {
     const variantPrice = parseInt(variantData.price);
     const exBtwPrice = Math.round(variantPrice / BTW_MULTIPLIER);

     
// Update BTW prijs
     if (typeof Shopify !== 'undefined' && Shopify.formatMoney) {
       btwPriceDisplay.textContent = Shopify.formatMoney(exBtwPrice, "{{ shop.money_format }}");
       if (incBtwPriceDisplay) {
         incBtwPriceDisplay.textContent = Shopify.formatMoney(variantPrice, "{{ shop.money_format }}");
       }
       if (incBtwPriceDisplayUnder) {
         incBtwPriceDisplayUnder.textContent = Shopify.formatMoney(variantPrice, "{{ shop.money_format }}");
       }
     } else {
       
// Fallback zonder Shopify.formatMoney
       const formattedExBtw = '€' + (exBtwPrice / 100).toFixed(2).replace('.', ',');
       const formattedInc = '€' + (variantPrice / 100).toFixed(2).replace('.', ',');

       btwPriceDisplay.textContent = formattedExBtw;
       if (incBtwPriceDisplay) incBtwPriceDisplay.textContent = formattedInc;
       if (incBtwPriceDisplayUnder) incBtwPriceDisplayUnder.textContent = formattedInc;
     }
   }
 }

 
// Luister naar variant-selects component
 const variantSelects = document.querySelector('variant-selects');
 if (variantSelects) {

   
// Luister naar radio button changes (swatch picker)
   const radioInputs = variantSelects.querySelectorAll('input[type="radio"]');
   radioInputs.forEach(input => {
     input.addEventListener('change', function() {
       setTimeout(() => {
         
// Check of er een hidden input is met variant ID
         const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
         if (hiddenInput && hiddenInput.value) {
           updateBTWPrices(hiddenInput.value);
         }
       }, 100);
     });
   });

   
// Luister naar select changes (dropdown picker)
   const selectInputs = variantSelects.querySelectorAll('select');
   selectInputs.forEach(select => {
     select.addEventListener('change', function() {
       setTimeout(() => {
         const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
         if (hiddenInput && hiddenInput.value) {
           updateBTWPrices(hiddenInput.value);
         }
       }, 100);
     });
   });

   
// Observeer DOM changes voor dynamische updates
   const observer = new MutationObserver((mutations) => {
     mutations.forEach((mutation) => {
       if (mutation.type === 'childList' || mutation.type === 'attributes') {
         const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
         if (hiddenInput && hiddenInput.value) {
           updateBTWPrices(hiddenInput.value);
         }
       }
     });
   });

   observer.observe(variantSelects, {
     childList: true,
     subtree: true,
     attributes: true,
     attributeFilter: ['data-selected-variant']
   });
 }

 
// Luister naar custom events
 document.addEventListener('variant:change', function(event) {
   if (event.detail && event.detail.variant && event.detail.variant.id) {
     updateBTWPrices(event.detail.variant.id);
   }
 });

 
// Fallback: observeer prijs wijzigingen
 const priceElement = document.querySelector('.price, .product__price, [data-price]');
 if (priceElement) {
   const priceObserver = new MutationObserver(() => {
     setTimeout(() => {
       const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
       if (hiddenInput && hiddenInput.value) {
         updateBTWPrices(hiddenInput.value);
       }
     }, 50);
   });

   priceObserver.observe(priceElement, { childList: true, subtree: true });
 }
});
</script>
{% endif %}

Wat doet deze code nou eigenlijk? Het eerste stuk (dat liquid gedeelte) rekent de BTW uit. Het is slim genoeg om te kijken of je product verschillende prijzen heeft (bijvoorbeeld verschillende maten met verschillende prijzen) en past zich daarop aan.

Het CSS stukje in het midden zorgt dat alles er netjes uitziet. En dat JavaScript onderaan? Dat is de toversaus die ervoor zorgt dat als iemand een andere variant kiest, de prijs meteen mee verandert. Geen pagina refresh nodig.

Stap 2: Het block koppelen aan je productpagina

Nu moeten we Shopify vertellen waar dit block moet komen. Zoek in je code editor het bestand main-product.liquid. Dit is het hoofdbestand van je productpagina's.

Open het bestand en zoek (met Ctrl+F of Cmd+F) naar {%- case block.type -%}. Dit staat meestal ergens tussen regel 200 en 400. Direct onder deze regel plak je:

liquid

{%- when 'price_ex_btw' -%}
   <div class="product-info__block product-info__block--sm product-price-ex-btw" {{ block.shopify_attributes }}>
     {% render 'price-ex-btw', product: product, block: block, use_variant: true, current_variant: current_variant %}
   </div>

Dit zegt eigenlijk tegen Shopify: "Hé, als iemand een price_ex_btw block toevoegt, gebruik dan onze snippet."

Stap 3: De instellingen toevoegen

Laatste technische stap. In hetzelfde main-product.liquid bestand scroll je helemaal naar beneden tot je {% schema %} ziet. Zoek daar naar "blocks": [ en plak direct daarna:

json

{
   "type": "price_ex_btw",
   "name": "⚡️ Prijs Excl. BTW",
   "limit": 1,
   "settings": [
     {
       "type": "header",
       "content": "⚡️ Prijs Exclusief BTW by Diek Thunnissen",
       "info": "Voeg prijzen exclusief BTW toe aan je product pagina."
     },
     {
       "type": "range",
       "id": "btw_percentage",
       "min": 1,
       "max": 30,
       "step": 1,
       "unit": "%",
       "label": "BTW percentage",
       "default": 21
     },
     {
       "type": "text",
       "id": "label_text",
       "label": "Label tekst",
       "default": "Excl. BTW:"
     },
     {
       "type": "checkbox",
       "id": "show_inc_btw",
       "label": "Toon ook prijs incl. BTW",
       "default": true
     },
     {
       "type": "text",
       "id": "inc_btw_label",
       "label": "Incl. BTW label",
       "default": "Incl. BTW:"
     },
     {
       "type": "select",
       "id": "inc_btw_placement",
       "label": "Incl. BTW weergave",
       "options": [
         {
           "value": "under",
           "label": "Onder excl. BTW"
         },
         {
           "value": "inline",
           "label": "Naast excl. BTW"
         }
       ],
       "default": "under"
     },
     {
       "type": "select",
       "id": "price_format",
       "label": "Prijsweergave bij prijsbereik",
       "options": [
         {
           "value": "from",
           "label": "Vanaf"
         },
         {
           "value": "range",
           "label": "Bereik (min-max)"
         }
       ],
       "default": "from"
     },
     {
       "type": "text",
       "id": "from_text",
       "label": "Vanaf tekst",
       "default": "Vanaf"
     },
     {
       "type": "text",
       "id": "range_separator",
       "label": "Bereik separator",
       "default": " - "
     },
     {
       "type": "header",
       "content": "Badge"
     },
     {
       "type": "checkbox",
       "id": "show_badge",
       "label": "Toon badge",
       "default": false
     },
     {
       "type": "text",
       "id": "badge_text",
       "label": "Badge tekst",
       "default": "Zakelijk"
     },
     {
       "type": "color",
       "id": "badge_bg_color",
       "label": "Badge achtergrondkleur",
       "default": "#f2f2f2"
     },
     {
       "type": "color",
       "id": "badge_text_color",
       "label": "Badge tekstkleur",
       "default": "#555555"
     },
     {
       "type": "range",
       "id": "badge_radius",
       "min": 0,
       "max": 20,
       "step": 1,
       "unit": "px",
       "label": "Badge hoekradius",
       "default": 4
     },
     {
       "type": "header",
       "content": "Styling"
     },
     {
       "type": "range",
       "id": "spacing",
       "min": 0,
       "max": 40,
       "step": 2,
       "unit": "px",
       "label": "Verticale ruimte",
       "default": 8
     },
     {
       "type": "range",
       "id": "font_size",
       "min": 10,
       "max": 24,
       "step": 1,
       "unit": "px",
       "label": "Lettergrootte",
       "default": 14
     },
     {
       "type": "color",
       "id": "label_color",
       "label": "Label kleur",
       "default": "#707070"
     },
     {
       "type": "color",
       "id": "price_color",
       "label": "Prijs kleur",
       "default": "#000000"
     },
     {
       "type": "select",
       "id": "label_weight",
       "label": "Label gewicht",
       "options": [
         {
           "value": "normal",
           "label": "Normaal"
         },
         {
           "value": "bold",
           "label": "Vet"
         },
         {
           "value": "500",
           "label": "Medium"
         }
       ],
       "default": "normal"
     },
     {
       "type": "select",
       "id": "label_style",
       "label": "Label stijl",
       "options": [
         {
           "value": "normal",
           "label": "Normaal"
         },
         {
           "value": "italic",
           "label": "Cursief"
         }
       ],
       "default": "normal"
     },
     {
       "type": "select",
       "id": "price_weight",
       "label": "Prijs gewicht",
       "options": [
         {
           "value": "normal",
           "label": "Normaal"
         },
         {
           "value": "bold",
           "label": "Vet"
         },
         {
           "value": "500",
           "label": "Medium"
         }
       ],
       "default": "bold"
     },
     {
       "type": "header",
       "content": "Geavanceerd"
     },
     {
       "type": "text",
       "id": "custom_class",
       "label": "Custom CSS class"
     },
     {
       "type": "liquid",
       "id": "custom_css",
       "label": "Custom CSS",
       "info": "Gebruik de .zakelijk-btw-container class als selector"
     }
   ]
},

Klaar! De code staat er nu in.

Het block gebruiken

Nu het leuke deel. Ga naar Online Store > Themes en klik op Customize. Open een productpagina en onder Product information zie je een Add block knop. Klik daarop en tadaa - daar staat je nieuwe ⚡️ Prijs Excl. BTW block.

Sleep het naar waar je het wilt hebben. Direct onder de prijs is vaak een goede plek, maar je kunt het ook bij de product details zetten. Zodra je het toevoegt, zie je rechts alle instellingen.

Slim configureren voor verschillende situaties

De standaard zakelijke setup

Voor de meeste B2B winkels werkt dit goed: zet het BTW percentage op 21%, vink "Toon ook prijs incl. BTW" aan, en kies voor weergave "Onder excl. BTW". Zo zie je beide prijzen netjes onder elkaar.

De subtiele variant

Wil je het wat minder opvallend? Maak de lettergrootte 12px, zet de labelkleur op lichtgrijs (#999999) en de prijskleur op donkergrijs (#666666). Dan staat de info er wel, maar valt het niet te veel op.

De premium look

Voor een echt professionele uitstraling zet je de "Zakelijk" badge aan. Kies een mooie achtergrondkleur die bij je merk past. Wil je het helemaal af maken? Voeg wat custom CSS toe:

css

.zakelijk-btw-container {
 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
 padding: 12px;
 background: #f8f9fa;
 border-radius: 8px;
}

Handige tips

Verschillende BTW percentages?

Heb je producten met verschillende BTW percentages? Geen probleem. Maak verschillende product templates aan in Shopify. Bijvoorbeeld eentje voor normale producten (21%), eentje voor voeding (9%) en eentje voor boeken (9%). In elk template stel je het juiste BTW percentage in.

Als het niet werkt

Meestal komt het door een typfoutje. Check vooral of alle komma's en accolades kloppen in de JSON. Eén missende komma en Shopify snapt er niks meer van.

Werken de variant prijzen niet? Kan gebeuren bij sommige thema's. Het block probeert verschillende manieren om de juiste prijs te vinden, maar soms moet je het JavaScript een beetje aanpassen voor jouw specifieke thema.

Thema updates

Het mooie is dat snippets bewaard blijven als je je thema update. Maar je moet wel de block settings opnieuw toevoegen aan main-product.liquid. Daarom is het slim om een backup te maken van je aangepaste code.

Waarom dit zo goed werkt

Het is niet alleen handig voor jou (geen gezeik meer met BTW vragen), maar je zakelijke klanten voelen zich ook serieus genomen. Ze zien meteen wat ze moeten betalen, kunnen makkelijk vergelijken en offertes maken.

En eerlijk is eerlijk - het ziet er ook gewoon professioneel uit. Het laat zien dat je nadenkt over verschillende soorten klanten en hun behoeften.

Tot slot

Je hebt nu een krachtige toevoeging aan je Shopify winkel. Test het vooral goed uit, vraag feedback aan je zakelijke klanten, en pas het aan waar nodig.

Loopt het ergens spaak of wil je iets speciaals? Stuur me gerust een mailtje. Ik help graag om het perfect te maken voor jouw situatie.

Over mij

Diek Thunnissen
Shopify Developer & E-commerce Specialist

Ik help webwinkels om beter te worden. Van kleine aanpassingen tot complete custom oplossingen - altijd met het doel om het leven van winkeliers én hun klanten makkelijker te maken.

🌐 diekthunnissen.nl
📧 info@diekthunnissen.nl

Succes met je nieuwe BTW functie!

Over Diek Thunnissen

Al sinds mijn vijftiende bouw ik websites. Nu, 10+ jaar en 50+ projecten verder, combineer ik design, Shopify‑development en data‑gedreven marketing tot één 360° e‑commerce‑aanpak.

User Icon - Personalfolio X Webflow Template
Meer over mij

Volg mij op social media

Check me op socials voor updates, tips en een kijkje achter de schermen.