diff --git a/InteractiveHtmlBom/core/fontparser.py b/InteractiveHtmlBom/core/fontparser.py
index 6f185e81..46cda679 100644
--- a/InteractiveHtmlBom/core/fontparser.py
+++ b/InteractiveHtmlBom/core/fontparser.py
@@ -42,6 +42,9 @@ def parse_font_char(self, chr):
 
     def parse_font_for_string(self, s):
         for c in s:
+            if c == '\t' and ' ' not in self.parsed_font:
+                # tabs rely on space char to calculate offset
+                self.parsed_font[' '] = self.parse_font_char(' ')
             if c not in self.parsed_font and ord(c) >= ord(' '):
                 self.parsed_font[c] = self.parse_font_char(c)
 
diff --git a/InteractiveHtmlBom/web/render.js b/InteractiveHtmlBom/web/render.js
index 57a73389..8fde8714 100644
--- a/InteractiveHtmlBom/web/render.js
+++ b/InteractiveHtmlBom/web/render.js
@@ -58,7 +58,12 @@ function drawtext(ctx, text, color, flip) {
     var offsety = (-(txt.length - 1) + i * 2) * interline + text.height / 2;
     var lineWidth = 0;
     for (var c of txt[i]) {
-      lineWidth += pcbdata.font_data[c].w * text.width;
+      if (c == '\t') {
+        var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
+        lineWidth += fourSpaces - lineWidth % fourSpaces;
+      } else {
+        lineWidth += pcbdata.font_data[c].w * text.width;
+      }
     }
     var offsetx = 0;
     switch (text.horiz_justify) {
@@ -75,6 +80,11 @@ function drawtext(ctx, text, color, flip) {
         break;
     }
     for (var c of txt[i]) {
+      if (c == '\t') {
+        var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
+        offsetx += fourSpaces - offsetx % fourSpaces;
+        continue;
+      }
       for (var line of pcbdata.font_data[c].l) {
         ctx.beginPath();
         ctx.moveTo(...calcFontPoint(line[0], text, offsetx, offsety, tilt));