diff --git a/theme/templates/base.html b/theme/templates/base.html
index a8397bdb742bd4835ddefba5c078aef1060918f8..5f51c79999630c110bf9148bc3914936e026158b 100644
--- a/theme/templates/base.html
+++ b/theme/templates/base.html
@@ -5,6 +5,7 @@
 {%- import 'macros/cards.html' as cards with context -%}
 {%- import 'macros/renderers.html' as render with context -%}
 {%- import 'macros/content_renderer.html' as content_renderer with context -%}
+{%- import 'macros/nav.html' as nav with context -%}
 
 <html lang="{%- block html_lang -%}{{ l }}{%- endblock html_lang -%}">
 <head>
@@ -40,28 +41,7 @@
 		<label for="show-header-menu" class="show-header-menu">&#9776;</label>
 		<input type="checkbox" id="show-header-menu" role="button">
 		<label for="show-header-menu" class="show-header-menu-bg"> </label>
-		<nav>
-			<ul>
-			{% for item in config.menuitems -%}
-				{%- if item.tag is defined -%}
-					{%- call(tagtitle, tagcolor, tagurl, tagpage, tagpages) get.tag_by_name(item.tag, l) -%}
-						<li style="--category-color: {{ tagcolor }}"><a href="{{ siteurl }}/{{ tagurl }}">{{ tagtitle|e }}</a></li>
-					{%- endcall -%}
-				{%- elif item.slug is defined -%}
-					{%- call(page) get.page_by_slug(item.slug, l) -%}
-					{%- call(cattitle, catcolor, caturl, catpage, catpages) get.tag_by_name(page.category, l) -%}
-						<li style="--category-color: {{ catcolor }}"><a href="{{ siteurl }}/{{ page.url }}">{{ page.title|e }}</a></li>
-					{%- endcall -%}
-					{%- endcall -%}
-				{%- else -%}
-					<br />
-					<strong>ERROR: menuitems: Cannot parse item: {{ item|string|e }}</strong><br />
-					<br />
-				{%- endif -%}
-				{#- TODO add active class if this is the current site -#}
-			{%- endfor %}
-			</ul>
-		</nav>
+		{{ nav.render_menu(config.menuitems, l) }}
 	</div>
 	<main>
 	{% block content %}
diff --git a/theme/templates/macros/nav.html b/theme/templates/macros/nav.html
new file mode 100644
index 0000000000000000000000000000000000000000..93c77dfefe76f3708e2ab66167eaa508e2e6205a
--- /dev/null
+++ b/theme/templates/macros/nav.html
@@ -0,0 +1,24 @@
+{%- import 'macros/link.html' as link with context -%}
+
+{%- macro render_menu(items, lang) -%}
+	<nav>
+		<ul>
+		{% for item in items -%}
+			{{ render_menu_item(item, lang) }}
+		{%- endfor %}
+		</ul>
+	</nav>
+{%- endmacro -%}
+
+{%- macro render_menu_item(item, lang) -%}
+	{%- if item is string -%}
+		{%- set url = item -%}
+		{%- call(parsedurl, anchor, reflang, is_external, reftype, refid, refpage, tagcattitle, tagcatcolor) link.parse_url(url, lang) -%}
+			<li style="--category-color: {{ tagcatcolor }}">
+				{{ link.render(url, None, lang) }}
+			</li>
+		{%- endcall -%}
+	{%- else -%}
+		TODO: handle custom menu items
+	{%- endif -%}
+{%- endmacro -%}