diff --git a/muppet/data/__init__.py b/muppet/data/__init__.py
index 9e685be9229845736a9327092935bf1480478c1e..6666e5bff2ff87264b85e38cb5bd8b85ed379265 100644
--- a/muppet/data/__init__.py
+++ b/muppet/data/__init__.py
@@ -22,6 +22,7 @@ from typing import (
 
 Markup: TypeAlias = Union[str,
                           'Tag',
+                          'Declaration',
                           'Link',
                           'ID',
                           'Documentation',
@@ -49,6 +50,20 @@ class Tag:
         return f'tag({repr(self.item)}, tags={self.tags})'
 
 
+@dataclass
+class Declaration(Tag):
+    """
+    Superset of tag, containing declaration statements.
+
+    Mostly used for class and resource parameters.
+
+    :param variable:
+        Name of the variable being declared.
+    """
+
+    variable: str
+
+
 @dataclass
 class Link:
     """An item which should link somewhere."""
@@ -103,6 +118,11 @@ def tag(item: Markup | Sequence[Markup], *tags: str) -> Tag:
     return Tag(item, tags=tags)
 
 
+def declaration(item: Markup | Sequence[Markup], *tags: str, variable: str) -> Declaration:
+    """Mark name of variable in declaration."""
+    return Declaration(item, tags=tags, variable=variable)
+
+
 def link(item: Markup, target: str) -> Link:
     """Create a new link element."""
     return Link(item, target)
diff --git a/muppet/data/html.py b/muppet/data/html.py
index 67edef91c2d06f15cf37d51dc38a991f459d6046..df4f0f2d25db0d54571eb675961ab9776146dae5 100644
--- a/muppet/data/html.py
+++ b/muppet/data/html.py
@@ -2,6 +2,7 @@
 
 from . import (
     Tag,
+    Declaration,
     Link,
     ID,
     Documentation,
@@ -11,10 +12,21 @@ from . import (
 )
 from collections.abc import Sequence
 import html
+from dataclasses import dataclass, field
 
 
+@dataclass
 class HTMLRenderer(Renderer):
-    """Render the document into HTML."""
+    """
+    Render the document into HTML.
+
+    :param param_documentation:
+        A dictionary containing (rendered) documentation for each
+        parameter of the class or resource type currently being
+        rendered.
+    """
+
+    param_documentation: dict[str, str] = field(default_factory=dict)
 
     def render_tag(self, tag: Tag) -> str:
         """Attaches all tags as classes in a span."""
@@ -26,8 +38,18 @@ class HTMLRenderer(Renderer):
         else:
             inner = render(self, tag.item)
 
+        out = ''
+        if isinstance(tag, Declaration):
+            if comment := self.param_documentation.get(tag.variable):
+                if isinstance(tag.item, list) \
+                        and tag.item \
+                        and isinstance(tag.item[0], Indentation):
+                    out += render(self, tag.item[0])
+                out += f'<span class="comment">{comment.strip()}</span>\n'
+
         tags = ' '.join(tag.tags)
-        return f'<span class="{tags}">{inner}</span>'
+        out += f'<span class="{tags}">{inner}</span>'
+        return out
 
     def render_link(self, link: Link) -> str:
         """Wrap the value in an anchor tag."""
diff --git a/muppet/format.py b/muppet/format.py
index c9bce7ccacfe568f0ca20c881b6cc7bcc4fdd48a..67aa5550530f35ed799c4dc049c11c9607583718 100644
--- a/muppet/format.py
+++ b/muppet/format.py
@@ -10,6 +10,7 @@ from commonmark import commonmark
 from subprocess import CalledProcessError
 import html
 import sys
+import re
 from typing import (
     Any,
     Literal,
@@ -29,6 +30,7 @@ from .data import (
     id,
     link,
     tag,
+    declaration,
     render,
 )
 from .data.html import (
@@ -260,18 +262,20 @@ def parse(form: Any, indent: int, context: list[str]) -> Tag:
             if 'params' in rest:
                 items += ['(', '\n']
                 for name, data in rest['params'].items():
-                    items += [ind(indent+1)]
+                    decls: list[Markup] = []
+                    decls += [ind(indent+1)]
                     if 'type' in data:
                         tt = parse(data['type'], indent+1, context)
-                        items += [tag(tt, 'type'),
+                        decls += [tag(tt, 'type'),
                                   ' ']
-                    items += [tag(f'${name}', 'var')]
+                    decls += [declare_var(name)]
                     if 'value' in data:
-                        items += [
+                        decls += [
                             ' ', '=', ' ',
                             # TODO this is a declaration
                             parse(data.get('value'), indent+1, context),
                         ]
+                    items += [declaration(decls, 'declaration', variable=name)]
                     items += [',', '\n']
                 items += [ind(indent), ')', ' ', '{', '\n']
             else:
@@ -320,18 +324,20 @@ def parse(form: Any, indent: int, context: list[str]) -> Tag:
             if params := rest.get('params'):
                 items += ['(', '\n']
                 for name, data in params.items():
-                    items += [ind(indent+1)]
+                    decl: list[Markup] = []
+                    decl += [ind(indent+1)]
                     if 'type' in data:
-                        items += [tag(parse(data['type'], indent, context),
-                                      'type'),
-                                  ' ']
+                        decl += [tag(parse(data['type'], indent, context),
+                                     'type'),
+                                 ' ']
                     # print(f'<span class="var">${name}</span>', end='')
-                    items += [declare_var(name)]
+                    decl += [declare_var(name)]
                     if 'value' in data:
-                        items += [
+                        decl += [
                             ' ', '=', ' ',
                             parse(data.get('value'), indent, context),
                         ]
+                    items += [declaration(decl, 'declaration', variable=name)]
                     items += [',', '\n']
 
                 items += [ind(indent), ')', ' ']
@@ -1050,8 +1056,20 @@ def print_docstring(name: str, docstring: dict[str, Any]) -> str:
     for t in tags:
         text = html.escape(t.get('text') or '')
         if t['tag_name'] == 'example':
-            out += f'<h3>{t["name"]}</h3>\n'
-            out += f'<pre><code class="puppet">{text}</code></pre>\n'
+            if name := t.get('name'):
+                out += f'<h3>{name}</h3>\n'
+            out += f'<pre class="example"><code class="puppet">{text}</code></pre>\n'
+
+    # out += '<dl>'
+    # for t in tags:
+    #     if t['tag_name'] == 'param':
+    #         out += f"<dt>{t['name']}</dt>"
+    #         if text := t.get('text'):
+    #             text = re.sub(r'(NOTE|TODO)',
+    #                           r'<mark>\1</mark>',
+    #                           commonmark(text))
+    #             out += f"<dd>{text}</dd>"
+    # out += '</dl>'
 
     if 'text' in docstring:
         out += '<div>'
@@ -1061,19 +1079,45 @@ def print_docstring(name: str, docstring: dict[str, Any]) -> str:
     return out
 
 
-renderer = HTMLRenderer()
+def build_param_dict(docstring: dict[str, Any]) -> dict[str, str]:
+    """
+    Extract all parameter documentation from a docstring dict.
+
+    :param docstring:
+        The object present under 'docstring' in the information about
+        a single object (class, resource, ...) in the output of
+        `puppet strings`.
+
+    :returns:
+        A dictionary where the keys are the variables which have
+        documentation, and the value is the (formatted) documentation
+        for that key. Undocumented keys (even those with the tag, but
+        no text) are ommitted from the resulting dictionary.
+    """
+    if tags := docstring.get('tags'):
+        obj = {}
+        for t in tags:
+            if t['tag_name'] == 'param':
+                if text := t.get('text'):
+                    obj[t['name']] = re.sub(r'(NOTE|TODO)',
+                                            r'<mark>\1</mark>',
+                                            commonmark(text))
+        return obj
+    else:
+        return {}
 
 
 def format_class(d_type: dict[str, Any]) -> str:
     """Format Puppet class."""
+    t = parse_puppet(d_type['source'])
+    data = parse(t, 0, ['root'])
+    renderer = HTMLRenderer(build_param_dict(d_type['docstring']))
     out = ''
     name = d_type['name']
     # print(name, file=sys.stderr)
-    print_docstring(name, d_type['docstring'])
+    out += print_docstring(name, d_type['docstring'])
 
     out += '<pre><code class="puppet">'
-    t = parse_puppet(d_type['source'])
-    data = parse(t, 0, ['root'])
     out += render(renderer, data)
     out += '</code></pre>'
     return out
@@ -1086,6 +1130,7 @@ def format_type() -> str:
 
 def format_type_alias(d_type: dict[str, Any]) -> str:
     """Format Puppet type alias."""
+    renderer = HTMLRenderer()
     out = ''
     name = d_type['name']
     # print(name, file=sys.stderr)
@@ -1101,6 +1146,7 @@ def format_type_alias(d_type: dict[str, Any]) -> str:
 
 def format_defined_type(d_type: dict[str, Any]) -> str:
     """Format Puppet defined type."""
+    renderer = HTMLRenderer(build_param_dict(d_type['docstring']))
     out = ''
     name = d_type['name']
     # print(name, file=sys.stderr)
diff --git a/static/highlight.css b/static/highlight.css
index 4949f3bca1b46cdfb86d2c543c362fcfc77ff60f..b3aa5d0258fc31d8225722eb7df395cd9a3fb304 100644
--- a/static/highlight.css
+++ b/static/highlight.css
@@ -43,3 +43,7 @@
 .string {
 	color: olive;
 }
+
+.comment {
+	color: grey;
+}
diff --git a/static/style.css b/static/style.css
index 43e414463086ecfc7359477e81074ee8f7d06ab9..fb19678a0ed02564100d9635f7bfad42d1827b0e 100644
--- a/static/style.css
+++ b/static/style.css
@@ -57,3 +57,26 @@ code.json {
 .overview-list p {
 	display: inline;
 }
+
+.example {
+	background: lightgray;
+	padding: 1em;
+	border-radius: 1ex;
+}
+
+.comment {
+	border-left: 1ex;
+	border-left-style: dotted;
+	display: inline-block;
+	padding-left: 1em;
+	font-family: sans;
+	font-size: 80%;
+}
+
+.comment p:first-child {
+	margin-top: 0;
+}
+
+.comment p:last-child {
+	margin-bottom: 0;
+}