diff --git a/sefht.geany b/sefht.geany
index 4ab8395323e7b153b7c5db618162831a086a7dbd..e976bd0587dd9ed774946160f5339af1b6befeea 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -28,7 +28,7 @@ long_line_behaviour=1
 long_line_column=72
 
 [files]
-current_page=8
+current_page=53
 FILE_NAME_0=139;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2FREADME;0;8
 FILE_NAME_1=134;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitignore;0;8
 FILE_NAME_2=1737;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8
@@ -37,7 +37,7 @@ FILE_NAME_4=19;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm
 FILE_NAME_5=1867;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2FMakefile.am;0;8
 FILE_NAME_6=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.c;0;8
 FILE_NAME_7=18;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fcms.h;0;8
-FILE_NAME_8=4132;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8
+FILE_NAME_8=4584;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.c;0;8
 FILE_NAME_9=1794;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fdata.h;0;8
 FILE_NAME_10=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.c;0;8
 FILE_NAME_11=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.h;0;8
@@ -60,11 +60,11 @@ FILE_NAME_27=900;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fpr
 FILE_NAME_28=1867;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext_mark_static.c;0;8
 FILE_NAME_29=2191;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8
 FILE_NAME_30=1159;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8
-FILE_NAME_31=1303;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_html.h;0;8
-FILE_NAME_32=10846;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8
-FILE_NAME_33=1068;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8
-FILE_NAME_34=1287;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag_data.h;0;8
-FILE_NAME_35=19943;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.c;0;8
+FILE_NAME_31=1008;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_html.h;0;8
+FILE_NAME_32=14105;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8
+FILE_NAME_33=1251;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8
+FILE_NAME_34=1150;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag_data.h;0;8
+FILE_NAME_35=22399;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.c;0;8
 FILE_NAME_36=1051;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr.h;0;8
 FILE_NAME_37=1413;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_attr_data.h;0;8
 FILE_NAME_38=924;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8
@@ -76,15 +76,15 @@ FILE_NAME_43=218;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp
 FILE_NAME_44=23;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
 FILE_NAME_45=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
 FILE_NAME_46=8232;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_fragment.c;0;8
-FILE_NAME_47=4446;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
+FILE_NAME_47=4815;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
 FILE_NAME_48=5714;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_fragment.c;0;8
 FILE_NAME_49=24;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
 FILE_NAME_50=4221;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
 FILE_NAME_51=994;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text_mark.c;0;8
 FILE_NAME_52=2447;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
-FILE_NAME_53=16197;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_tag.c;0;8
-FILE_NAME_54=57386;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_attr.c;0;8
-FILE_NAME_55=85;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
+FILE_NAME_53=9430;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_tag.c;0;8
+FILE_NAME_54=58751;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator_attr.c;0;8
+FILE_NAME_55=497;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8
 FILE_NAME_56=201;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitlab-ci.yml;0;4
 FILE_NAME_57=71;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Fupload.sh.in;0;8
 FILE_NAME_58=806;Sh;0;EUTF-8;0;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fgitlab-ci%2Frelease.sh.in;0;4
diff --git a/src/lib/sefht/data.c b/src/lib/sefht/data.c
index 1ca38c06e287c9fe778b95baa75b2d8174844e23..8211a31412bd9d75adf9a826db801bce4c915c8f 100644
--- a/src/lib/sefht/data.c
+++ b/src/lib/sefht/data.c
@@ -168,31 +168,39 @@ init_validator (struct SH_Data * data,
 		return FALSE;
 	}
 
-	SH_Validator_register_tag (data->validator, "html", NULL);
-	SH_Validator_register_tag (data->validator, "head", NULL);
-	SH_Validator_register_tag (data->validator, "body", NULL);
-	SH_Validator_register_tag (data->validator, "meta", NULL);
-	SH_Validator_register_tag (data->validator, "link", NULL);
-	SH_Validator_register_tag (data->validator, "title", NULL);
-	SH_Validator_register_tag (data->validator, "main", NULL);
-	SH_Validator_register_tag (data->validator, "article", NULL);
-	SH_Validator_register_tag (data->validator, "section", NULL);
-	SH_Validator_register_tag (data->validator, "header", NULL);
-	SH_Validator_register_tag (data->validator, "footer", NULL);
-	SH_Validator_register_tag (data->validator, "nav", NULL);
-	SH_Validator_register_tag (data->validator, "h1", NULL);
-	SH_Validator_register_tag (data->validator, "h2", NULL);
-	SH_Validator_register_tag (data->validator, "h3", NULL);
-	SH_Validator_register_tag (data->validator, "h4", NULL);
-	SH_Validator_register_tag (data->validator, "h5", NULL);
-	SH_Validator_register_tag (data->validator, "h6", NULL);
-	SH_Validator_register_tag (data->validator, "p", NULL);
-	SH_Validator_register_tag (data->validator, "br", NULL);
-	SH_Validator_register_tag (data->validator, "i", NULL);
-	SH_Validator_register_tag (data->validator, "b", NULL);
-	SH_Validator_register_tag (data->validator, "strong", NULL);
-	SH_Validator_register_tag (data->validator, "em", NULL);
-	SH_Validator_register_tag (data->validator, "small", NULL);
+	#define R(...)                                                 \
+	if (!SH_Validator_register_tag (data->validator,               \
+	                                __VA_ARGS__, NULL))            \
+	{                                                              \
+		SH_Validator_free (data->validator);                   \
+		return FALSE;                                          \
+	}
+	R("html", SH_TAG_TYPE_NORMAL);
+	R("head", SH_TAG_TYPE_NORMAL);
+	R("body", SH_TAG_TYPE_NORMAL);
+	R("meta", SH_TAG_TYPE_VOID);
+	R("link", SH_TAG_TYPE_VOID);
+	R("title", SH_TAG_TYPE_ESC_RAW_TEXT);
+	R("main", SH_TAG_TYPE_NORMAL);
+	R("article", SH_TAG_TYPE_NORMAL);
+	R("section", SH_TAG_TYPE_NORMAL);
+	R("header", SH_TAG_TYPE_NORMAL);
+	R("footer", SH_TAG_TYPE_NORMAL);
+	R("nav", SH_TAG_TYPE_NORMAL);
+	R("h1", SH_TAG_TYPE_NORMAL);
+	R("h2", SH_TAG_TYPE_NORMAL);
+	R("h3", SH_TAG_TYPE_NORMAL);
+	R("h4", SH_TAG_TYPE_NORMAL);
+	R("h5", SH_TAG_TYPE_NORMAL);
+	R("h6", SH_TAG_TYPE_NORMAL);
+	R("p", SH_TAG_TYPE_NORMAL);
+	R("br", SH_TAG_TYPE_VOID);
+	R("i", SH_TAG_TYPE_NORMAL);
+	R("b", SH_TAG_TYPE_NORMAL);
+	R("strong", SH_TAG_TYPE_NORMAL);
+	R("em", SH_TAG_TYPE_NORMAL);
+	R("small", SH_TAG_TYPE_NORMAL);
+	#undef R
 
 	return TRUE;
 }
diff --git a/src/lib/sefht/validator_attr.c b/src/lib/sefht/validator_attr.c
index b566c6b4d7259cfc4f92ab25cf9aef86bfe23281..3482f126530e3c2340442df3d9374232aa2cd188 100644
--- a/src/lib/sefht/validator_attr.c
+++ b/src/lib/sefht/validator_attr.c
@@ -286,9 +286,9 @@ init_attr_from_spec (/*@special@*/ struct SH_Validator * validator,
 		const char * tag;
 
 		tag = spec.tags[index].tag;
-		if ((!find_tag (validator, tag, &position))
-		&& (!add_tag (validator, tag, position, status)))
+		if (!find_tag (validator, tag, &position))
 		{
+			set_status (status, E_STATE, 2, "no such tag");
 			free (attr_data->name);
 			free (attr_data->tags);
 			return FALSE;
@@ -969,9 +969,9 @@ SH_Validator_register_attr (struct SH_Validator * validator,
 
 	if (NULL != tag)
 	{
-		if ((!find_tag (validator, tag, &index))
-		&& (!add_tag (validator, tag, index, status)))
+		if (!find_tag (validator, tag, &index))
 		{
+			set_status (status, E_STATE, 2, "no such tag");
 			return FALSE;
 		}
 
diff --git a/src/lib/sefht/validator_html.h b/src/lib/sefht/validator_html.h
index f952eb2c0f4bb762f26939ad402b2bf07662b143..79268b5fcce86f20224949d66658d57f37760011 100644
--- a/src/lib/sefht/validator_html.h
+++ b/src/lib/sefht/validator_html.h
@@ -29,9 +29,13 @@
 #error "Only <sefht/sefht.h> can be included directly."
 #endif
 
+#include "validator.h"
+
+
 struct HTML_TAG_DEFINITION
 {
 	/*@observer@*/ const char * tag;
+	enum SH_VALIDATOR_TAG_TYPE type;
 };
 
 struct HTML_ATTR_DEFINITION
diff --git a/src/lib/sefht/validator_tag.c b/src/lib/sefht/validator_tag.c
index ebd6e7a5678065b2edcbcf20092d9bd750208624..388d90368a003826d7e744860648a756c7aca9bb 100644
--- a/src/lib/sefht/validator_tag.c
+++ b/src/lib/sefht/validator_tag.c
@@ -36,6 +36,18 @@
 #include "validator_html.h"
 
 
+static inline
+bool
+tag_type_to_internal (/*@out@*/ enum TAG_TYPE * internal,
+                      enum SH_VALIDATOR_TAG_TYPE external)
+	/*@modifies internal@*/;
+
+/*@unused@*/
+static inline
+enum SH_VALIDATOR_TAG_TYPE
+tag_type_to_external (enum TAG_TYPE type)
+	/*@*/;
+
 static inline
 void
 init_tags (/*@special@*/ struct SH_Validator * validator)
@@ -106,6 +118,7 @@ static inline
 bool
 add_tag (struct SH_Validator * validator,
          const char * tag,
+         enum TAG_TYPE type,
          size_t index,
          /*@null@*/ /*@out@*/ struct SH_Status * status)
 	/*@modifies validator->tags@*/
@@ -126,6 +139,60 @@ remove_tag (struct SH_Validator * validator,
 	/*@modifies status@*/;
 
 
+static inline
+bool
+tag_type_to_internal (/*@out@*/ enum TAG_TYPE * internal,
+                      enum SH_VALIDATOR_TAG_TYPE external)
+	/*@modifies internal@*/
+{
+	switch (external)
+	{
+		case SH_TAG_TYPE_VOID:
+			*internal = TAG_T_VOID;
+			return TRUE;
+
+		case SH_TAG_TYPE_TEMPLATE:
+			*internal = TAG_T_TEMPLATE;
+			return TRUE;
+
+		case SH_TAG_TYPE_RAW_TEXT:
+			*internal = TAG_T_RAW_TEXT;
+			return TRUE;
+
+		case SH_TAG_TYPE_ESC_RAW_TEXT:
+			*internal = TAG_T_ESC_RAW_TEXT;
+			return TRUE;
+
+		case SH_TAG_TYPE_FOREIGN:
+			*internal = TAG_T_FOREIGN;
+			return TRUE;
+
+		case SH_TAG_TYPE_NORMAL:
+			*internal = TAG_T_NORMAL;
+			return TRUE;
+
+		default:
+			return FALSE;
+	}
+}
+
+/*@unused@*/
+static inline
+enum SH_VALIDATOR_TAG_TYPE
+tag_type_to_external (enum TAG_TYPE type)
+	/*@*/
+{
+	switch (type)
+	{
+		case TAG_T_VOID: return SH_TAG_TYPE_VOID;
+		case TAG_T_TEMPLATE: return SH_TAG_TYPE_TEMPLATE;
+		case TAG_T_RAW_TEXT: return SH_TAG_TYPE_RAW_TEXT;
+		case TAG_T_ESC_RAW_TEXT: return SH_TAG_TYPE_ESC_RAW_TEXT;
+		case TAG_T_FOREIGN: return SH_TAG_TYPE_FOREIGN;
+		case TAG_T_NORMAL: return SH_TAG_TYPE_NORMAL;
+	}
+}
+
 static inline
 void
 init_tags (/*@special@*/ struct SH_Validator * validator)
@@ -201,6 +268,15 @@ init_tags_from_spec (/*@special@*/ struct SH_Validator * validator,
 		{
 			struct tag_info tag_data;
 
+			if (!tag_type_to_internal (&tag_data.type,
+			                           spec[index].type))
+			{
+				set_status (status, E_VALUE, 3,
+				            "invalid tag type");
+				free_tags (validator);
+				return FALSE;
+			}
+
 			tag_data.name = strdup (spec[index].tag);
 			if (NULL == tag_data.name)
 			{
@@ -233,6 +309,8 @@ copy_tag (/*@special@*/ struct tag_info * copy,
           /*@null@*/ /*@out@*/ struct SH_Status * status)
 	/*@defines copy->name@*/
 	/*@modifies copy->name@*/
+	/*@defines copy->type@*/
+	/*@modifies copy->type@*/
 	/*@globals fileSystem@*/
 	/*@modifies fileSystem@*/
 	/*@modifies status@*/
@@ -247,6 +325,7 @@ copy_tag (/*@special@*/ struct tag_info * copy,
 	}
 
 	copy->name = name;
+	copy->type = tag->type;
 	return TRUE;
 
 }
@@ -363,6 +442,7 @@ static inline
 bool
 add_tag (struct SH_Validator * validator,
          const char * tag,
+         enum TAG_TYPE type,
          size_t index,
          /*@null@*/ /*@out@*/ struct SH_Status * status)
 	/*@modifies validator->tags@*/
@@ -392,6 +472,8 @@ add_tag (struct SH_Validator * validator,
 		return FALSE;
 	}
 
+	tag_data.type = type;
+
 	/* allocate new space */
 	/* The addition and the multiplication is save,
 	 * because we have tested for this
@@ -509,6 +591,7 @@ bool
 /*@alt void@*/
 SH_Validator_register_tag (struct SH_Validator * validator,
                            const char * tag,
+                           enum SH_VALIDATOR_TAG_TYPE type,
                            /*@null@*/ /*@out@*/
                            struct SH_Status * status)
 	/*@modifies validator->tags@*/
@@ -518,15 +601,24 @@ SH_Validator_register_tag (struct SH_Validator * validator,
 	/*@modifies status@*/
 {
 	size_t index;
+	enum TAG_TYPE type_internal;
+
+	if (!tag_type_to_internal (&type_internal, type))
+	{
+		set_status (status, E_VALUE, 2, "invalid tag type");
+		return FALSE;
+	}
 
 	/* tag already registered */
 	if (find_tag (validator, tag, &index))
 	{
+		/* update type */
+		validator->tags[index].type = type_internal;
 		set_success (status);
 		return TRUE;
 	}
 
-	return add_tag (validator, tag, index, status);
+	return add_tag (validator, tag, type_internal, index, status);
 }
 
 bool
diff --git a/src/lib/sefht/validator_tag.h b/src/lib/sefht/validator_tag.h
index 4d3d6ae4042c882fbc58ce99141398cc79f5bd91..83b5c1046d21325517a2d7097cdfce75cda9c389 100644
--- a/src/lib/sefht/validator_tag.h
+++ b/src/lib/sefht/validator_tag.h
@@ -36,10 +36,23 @@
 #include "status.h"
 
 
+enum SH_VALIDATOR_TAG_TYPE
+{
+	SH_TAG_TYPE_UNDEFINED,
+	SH_TAG_TYPE_VOID,
+	SH_TAG_TYPE_TEMPLATE,
+	SH_TAG_TYPE_RAW_TEXT,
+	SH_TAG_TYPE_ESC_RAW_TEXT,
+	SH_TAG_TYPE_FOREIGN,
+	SH_TAG_TYPE_NORMAL,
+};
+
+
 bool
 /*@alt void@*/
 SH_Validator_register_tag (SH_Validator * validator,
                            const char * tag,
+                           enum SH_VALIDATOR_TAG_TYPE type,
                            /*@null@*/ /*@out@*/
                            struct SH_Status * status)
 	/*@modifies validator@*/
diff --git a/src/lib/sefht/validator_tag_data.h b/src/lib/sefht/validator_tag_data.h
index b8ea9636756038b459d8dff35555149c0ab5196a..2809cd0f687d7c588ce4c005f9615ac0191831eb 100644
--- a/src/lib/sefht/validator_tag_data.h
+++ b/src/lib/sefht/validator_tag_data.h
@@ -29,9 +29,20 @@
 #error "Only <sefht/sefht.h> can be included directly."
 #endif
 
+enum TAG_TYPE
+{
+	TAG_T_VOID,
+	TAG_T_TEMPLATE,
+	TAG_T_RAW_TEXT,
+	TAG_T_ESC_RAW_TEXT,
+	TAG_T_FOREIGN,
+	TAG_T_NORMAL,
+};
+
 struct tag_info
 {
 	/*@only@*/ char * name;
+	enum TAG_TYPE type;
 };
 
 #define TAG_DATA                                                       \
diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c
index d64afc437c98dcfbb0edb43f7f7919591a1a60dc..70673f2f59b00f704a79c8692930b29d402945f4 100644
--- a/tests/test_node_fragment.c
+++ b/tests/test_node_fragment.c
@@ -50,7 +50,8 @@ START_TEST(test_node_fragment_no_status)
 	data = SH_Data_new (NULL);
 	ck_assert_ptr_ne (NULL, data);
 
-	result = SH_Validator_register_tag (data->validator, tag, NULL);
+	result = SH_Validator_register_tag (data->validator, tag,
+	                                    SH_TAG_TYPE_NORMAL, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	/* test - invalid tag */
@@ -91,7 +92,8 @@ START_TEST(test_node_fragment_with_status)
 	data = SH_Data_new (NULL);
 	ck_assert_ptr_ne (NULL, data);
 
-	result = SH_Validator_register_tag (data->validator, tag, NULL);
+	result = SH_Validator_register_tag (data->validator, tag,
+	                                    SH_TAG_TYPE_NORMAL, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	/* test - invalid tag */
@@ -135,7 +137,8 @@ START_TEST(test_node_fragment_raw_no_status)
 	data = SH_Data_new (NULL);
 	ck_assert_ptr_ne (NULL, data);
 
-	result = SH_Validator_register_tag (data->validator, tag, NULL);
+	result = SH_Validator_register_tag (data->validator, tag,
+	                                    SH_TAG_TYPE_NORMAL, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	/* test - invalid tag */
@@ -177,7 +180,8 @@ START_TEST(test_node_fragment_raw_with_status)
 	data = SH_Data_new (NULL);
 	ck_assert_ptr_ne (NULL, data);
 
-	result = SH_Validator_register_tag (data->validator, tag, NULL);
+	result = SH_Validator_register_tag (data->validator, tag,
+	                                    SH_TAG_TYPE_NORMAL, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	/* test - invalid tag */
diff --git a/tests/test_validator_attr.c b/tests/test_validator_attr.c
index 752ef28f476f53e11aa73071b1f8167f276ee536..f18979118698b508f780d887be5e2e77dfeaf208 100644
--- a/tests/test_validator_attr.c
+++ b/tests/test_validator_attr.c
@@ -42,10 +42,10 @@
 #include "validator_html.h"
 
 const struct HTML_TAG_DEFINITION HTML_TAGS[] = {
-	{"html"},
-	{"aside"},
-	{"a"},
-	{"p"},
+	{"html", SH_TAG_TYPE_NORMAL},
+	{"aside", SH_TAG_TYPE_NORMAL},
+	{"a", SH_TAG_TYPE_NORMAL},
+	{"p", SH_TAG_TYPE_NORMAL},
 };
 
 const struct HTML_ATTR_DEFINITION HTML_ATTRS[] = {
@@ -361,10 +361,11 @@ START_TEST(test_validator_attr_register_no_status)
 {
 	struct SH_Validator * validator;
 	const char * tag1 = "html";
-	const char * tag2 = "foobarbaz"; // mustn't be registered yet
+	const char * tag2 = "form";
 	const char * tag3 = "body";
 	const char * tag4 = "nav";
 	const char * tag5 = "aside";
+	const char * notag = "foobarbaz"; // mustn't be registered
 	const char * attr1 = "id";
 	const char * attr2 = "class";
 	const char * attr3 = "name";
@@ -378,6 +379,19 @@ START_TEST(test_validator_attr_register_no_status)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, tag1, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag2, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag3, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag4, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag5, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
+
 	/* test - register */
 	result = SH_Validator_register_attr (validator, tag1, attr1,
 	                                     NULL);
@@ -404,7 +418,7 @@ START_TEST(test_validator_attr_register_no_status)
 	ck_assert_ptr_ne (tag1, validator->attrs[0].tags[0].name);
 	ck_assert_str_eq (tag1, validator->attrs[0].tags[0].name);
 
-	/* test - automatic tag register */
+	/* test - register #2 */
 	result = SH_Validator_register_attr (validator, tag2, attr1,
 	                                     NULL);
 	ck_assert_int_eq (TRUE, result);
@@ -413,6 +427,15 @@ START_TEST(test_validator_attr_register_no_status)
 	ck_assert_ptr_ne (attr1, validator->attrs[0].name);
 	ck_assert_str_eq (attr1, validator->attrs[0].name);
 
+	/* test - register unknown tag */
+	result = SH_Validator_register_attr (validator, notag, attr1,
+	                                     NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	ck_assert_int_eq (1, validator->attr_n);
+	ck_assert_ptr_ne (attr1, validator->attrs[0].name);
+	ck_assert_str_eq (attr1, validator->attrs[0].name);
+
 	#define TEST_STR(S1, S2) ck_assert_ptr_ne (S1, S2);            \
 	                         ck_assert_str_eq (S1, S2);
 
@@ -562,10 +585,11 @@ START_TEST(test_validator_attr_register_with_status)
 	struct SH_Status status;
 	struct SH_Validator * validator;
 	const char * tag1 = "html";
-	const char * tag2 = "foobarbaz"; // mustn't be registered yet
+	const char * tag2 = "form";
 	const char * tag3 = "body";
 	const char * tag4 = "nav";
 	const char * tag5 = "aside";
+	const char * notag = "foobarbaz"; // mustn't be registered
 	const char * attr1 = "id";
 	const char * attr2 = "class";
 	const char * attr3 = "name";
@@ -579,6 +603,19 @@ START_TEST(test_validator_attr_register_with_status)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, tag1, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag2, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag3, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag4, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag5, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
+
 	/* test - register */
 	_status_preinit (status);
 	result = SH_Validator_register_attr (validator, tag1, attr1,
@@ -609,7 +646,7 @@ START_TEST(test_validator_attr_register_with_status)
 	ck_assert_ptr_ne (tag1, validator->attrs[0].tags[0].name);
 	ck_assert_str_eq (tag1, validator->attrs[0].tags[0].name);
 
-	/* test - automatic tag register */
+	/* test - register #2 */
 	_status_preinit (status);
 	result = SH_Validator_register_attr (validator, tag2, attr1,
 	                                     &status);
@@ -620,6 +657,17 @@ START_TEST(test_validator_attr_register_with_status)
 	ck_assert_ptr_ne (attr1, validator->attrs[0].name);
 	ck_assert_str_eq (attr1, validator->attrs[0].name);
 
+	/* test - register unknown tag */
+	_status_preinit (status);
+	result = SH_Validator_register_attr (validator, notag, attr1,
+	                                     &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_STATE, status.status);
+
+	ck_assert_int_eq (1, validator->attr_n);
+	ck_assert_ptr_ne (attr1, validator->attrs[0].name);
+	ck_assert_str_eq (attr1, validator->attrs[0].name);
+
 	#define TEST_STR(S1, S2) ck_assert_ptr_ne (S1, S2);            \
 	                         ck_assert_str_eq (S1, S2);
 
@@ -797,6 +845,13 @@ START_TEST(test_validator_attr_deregister_no_status)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, "html", V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, "body", V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
+
 	#define REGISTER SH_Validator_register_attr
 	result = REGISTER (validator, "html", "attr", NULL);
 	ck_assert_int_eq (TRUE, result);
@@ -1113,6 +1168,11 @@ START_TEST(test_validator_attr_deregister_no_status)
 	ck_assert_ptr_eq (NULL, validator->attrs[0].tags);
 
 	/* undo auto remove */
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, "body", V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
+
 	#define REGISTER SH_Validator_register_attr
 	result = REGISTER (validator, "body", "id", NULL);
 	ck_assert_int_eq (TRUE, result);
@@ -1165,6 +1225,13 @@ START_TEST(test_validator_attr_deregister_with_status)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, "html", V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, "body", V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
+
 	#define REGISTER SH_Validator_register_attr
 	result = REGISTER (validator, "html", "attr", NULL);
 	ck_assert_int_eq (TRUE, result);
@@ -1509,6 +1576,11 @@ START_TEST(test_validator_attr_deregister_with_status)
 	ck_assert_ptr_eq (NULL, validator->attrs[0].tags);
 
 	/* undo auto remove */
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, "body", V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
+
 	#define REGISTER SH_Validator_register_attr
 	result = REGISTER (validator, "body", "id", NULL);
 	ck_assert_int_eq (TRUE, result);
@@ -1569,6 +1641,12 @@ START_TEST(test_validator_attr_check)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, tag_1, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	result = SH_Validator_register_tag (validator, tag_2, V, NULL);
+	ck_assert_int_eq (TRUE, result);
+	#undef V
 
 	#define REGISTER SH_Validator_register_attr
 	result = REGISTER (validator, tag_1, attr_1, NULL);
diff --git a/tests/test_validator_tag.c b/tests/test_validator_tag.c
index aec3ec7cf5018fca24fe2175eff7b2ccdc6e32d4..800c1a9f77623e206226fd5446f5f75f22e18e89 100644
--- a/tests/test_validator_tag.c
+++ b/tests/test_validator_tag.c
@@ -40,10 +40,10 @@
 /* override HTML spec */
 #include "validator_html.h"
 const struct HTML_TAG_DEFINITION HTML_TAGS[] = {
-	{"html"},
-	{"aside"},
-	{"html"},
-	{"body"}
+	{"html", SH_TAG_TYPE_NORMAL},
+	{"aside", SH_TAG_TYPE_ESC_RAW_TEXT},
+	{"html", SH_TAG_TYPE_VOID},
+	{"body", SH_TAG_TYPE_TEMPLATE}
 };
 #define HTML5_TAGS HTML_TAGS
 
@@ -99,10 +99,12 @@ START_TEST(test_validator_tag_copy_no_status)
 
 	#define TEST_STR(S) ck_assert_ptr_ne (validator->S, copy->S);  \
 	                    ck_assert_str_eq (validator->S, copy->S);
+	#define TEST_INT(I) ck_assert_int_eq (validator->I, copy->I);
 
 	for (size_t index = 0; index < copy->tag_n; index++)
 	{
 		TEST_STR (tags[index].name);
+		TEST_INT (tags[index].type);
 	}
 
 	#undef TEST_STR
@@ -134,10 +136,12 @@ START_TEST(test_validator_tag_copy_with_status)
 
 	#define TEST_STR(S) ck_assert_ptr_ne (validator->S, copy->S);  \
 	                    ck_assert_str_eq (validator->S, copy->S);
+	#define TEST_INT(I) ck_assert_int_eq (validator->I, copy->I);
 
 	for (size_t index = 0; index < copy->tag_n; index++)
 	{
 		TEST_STR (tags[index].name);
+		TEST_INT (tags[index].type);
 	}
 
 	#undef TEST_STR
@@ -160,12 +164,15 @@ START_TEST(test_validator_tag_spec_no_status)
 
 	ck_assert_ptr_ne (HTML_TAGS[1].tag, validator->tags[0].name);
 	ck_assert_str_eq (HTML_TAGS[1].tag, validator->tags[0].name);
+	ck_assert_int_eq (TAG_T_ESC_RAW_TEXT, validator->tags[0].type);
 
 	ck_assert_ptr_ne (HTML_TAGS[3].tag, validator->tags[1].name);
 	ck_assert_str_eq (HTML_TAGS[3].tag, validator->tags[1].name);
+	ck_assert_int_eq (TAG_T_TEMPLATE, validator->tags[1].type);
 
 	ck_assert_ptr_ne (HTML_TAGS[0].tag, validator->tags[2].name);
 	ck_assert_str_eq (HTML_TAGS[0].tag, validator->tags[2].name);
+	ck_assert_int_eq (TAG_T_NORMAL, validator->tags[2].type);
 
 	/* cleanup */
 	SH_Validator_free (validator);
@@ -188,12 +195,15 @@ START_TEST(test_validator_tag_spec_with_status)
 
 	ck_assert_ptr_ne (HTML_TAGS[1].tag, validator->tags[0].name);
 	ck_assert_str_eq (HTML_TAGS[1].tag, validator->tags[0].name);
+	ck_assert_int_eq (TAG_T_ESC_RAW_TEXT, validator->tags[0].type);
 
 	ck_assert_ptr_ne (HTML_TAGS[3].tag, validator->tags[1].name);
 	ck_assert_str_eq (HTML_TAGS[3].tag, validator->tags[1].name);
+	ck_assert_int_eq (TAG_T_TEMPLATE, validator->tags[1].type);
 
 	ck_assert_ptr_ne (HTML_TAGS[0].tag, validator->tags[2].name);
 	ck_assert_str_eq (HTML_TAGS[0].tag, validator->tags[2].name);
+	ck_assert_int_eq (TAG_T_NORMAL, validator->tags[2].type);
 
 	/* cleanup */
 	SH_Validator_free (validator);
@@ -211,34 +221,48 @@ START_TEST(test_validator_tag_register_no_status)
 	char * tagN;
 	bool result;
 
+	#define V SH_TAG_TYPE_VOID
+
 	/* setup */
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
 	/* test - register */
-	result = SH_Validator_register_tag (validator, tag1, NULL);
+	result = SH_Validator_register_tag (validator, tag1,
+	                                    SH_TAG_TYPE_VOID, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	ck_assert_int_eq (1, validator->tag_n);
 	ck_assert_ptr_ne (tag1, validator->tags[0].name);
 	ck_assert_str_eq (tag1, validator->tags[0].name);
+	ck_assert_int_eq (TAG_T_VOID, validator->tags[0].type);
+
+	/* test - invalid type */
+	result = SH_Validator_register_tag (validator, tag2, -1, NULL);
+	ck_assert_int_eq (FALSE, result);
 
 	/* test - duplicate registration */
-	result = SH_Validator_register_tag (validator, tag1, NULL);
+	result = SH_Validator_register_tag (validator, tag1,
+	                                    SH_TAG_TYPE_NORMAL, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	ck_assert_int_eq (1, validator->tag_n);
 	ck_assert_ptr_ne (tag1, validator->tags[0].name);
 	ck_assert_str_eq (tag1, validator->tags[0].name);
+	ck_assert_int_eq (TAG_T_NORMAL, validator->tags[0].type);
+
+	/* test - duplicate invalid type */
+	result = SH_Validator_register_tag (validator, tag1, 20, NULL);
+	ck_assert_int_eq (FALSE, result);
 
 	/* test - order */
-	result = SH_Validator_register_tag (validator, tag3, NULL);
+	result = SH_Validator_register_tag (validator, tag3, V, NULL);
 	ck_assert_int_eq (TRUE, result);
 
-	result = SH_Validator_register_tag (validator, tag4, NULL);
+	result = SH_Validator_register_tag (validator, tag4, V, NULL);
 	ck_assert_int_eq (TRUE, result);
 
-	result = SH_Validator_register_tag (validator, tag5, NULL);
+	result = SH_Validator_register_tag (validator, tag5, V, NULL);
 	ck_assert_int_eq (TRUE, result);
 
 	ck_assert_int_eq (4, validator->tag_n);
@@ -264,16 +288,18 @@ START_TEST(test_validator_tag_register_no_status)
 	{
 		sprintf (tagN, "tag%zu", validator->tag_n);
 	}
-	while (SH_Validator_register_tag (validator, tagN, NULL));
+	while (SH_Validator_register_tag (validator, tagN, V, NULL));
 
 	free (tagN);
 
 	/* test overflow */
-	result = SH_Validator_register_tag (validator, tag2, NULL);
+	result = SH_Validator_register_tag (validator, tag2, V, NULL);
 	ck_assert_int_eq (FALSE, result);
 
 	ck_assert_int_eq (10, validator->tag_n);
 
+	#undef V
+
 	/* cleanup */
 	/* also free garbage created for overflow test */
 	validator->tag_n = 10;
@@ -292,43 +318,61 @@ START_TEST(test_validator_tag_register_with_status)
 	char * tagN;
 	bool result;
 
+	#define V SH_TAG_TYPE_VOID
+
 	/* setup */
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
 	/* test - register */
 	_status_preinit (status);
-	result = SH_Validator_register_tag (validator, tag1, &status);
+	result = SH_Validator_register_tag (validator, tag1,
+	                                    SH_TAG_TYPE_VOID, &status);
 	ck_assert_int_eq (TRUE, result);
 	ck_assert_int_eq (SUCCESS, status.status);
 
 	ck_assert_int_eq (1, validator->tag_n);
 	ck_assert_ptr_ne (tag1, validator->tags[0].name);
 	ck_assert_str_eq (tag1, validator->tags[0].name);
+	ck_assert_int_eq (TAG_T_VOID, validator->tags[0].type);
+
+	/* test - invalid type */
+	_status_preinit (status);
+	result = SH_Validator_register_tag (validator, tag2, -1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_VALUE, status.status);
 
 	/* test - duplicate registration */
 	_status_preinit (status);
-	result = SH_Validator_register_tag (validator, tag1, &status);
+	result = SH_Validator_register_tag (validator, tag1,
+	                                    SH_TAG_TYPE_NORMAL, &status);
 	ck_assert_int_eq (TRUE, result);
 	ck_assert_int_eq (SUCCESS, status.status);
 
 	ck_assert_int_eq (1, validator->tag_n);
 	ck_assert_ptr_ne (tag1, validator->tags[0].name);
 	ck_assert_str_eq (tag1, validator->tags[0].name);
+	ck_assert_int_eq (TAG_T_NORMAL, validator->tags[0].type);
+
+	/* test - duplicate invalid type */
+	_status_preinit (status);
+	result = SH_Validator_register_tag (validator, tag1, 20, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert_int_eq (E_VALUE, status.status);
 
 	/* test - order */
 	_status_preinit (status);
-	result = SH_Validator_register_tag (validator, tag3, &status);
+	result = SH_Validator_register_tag (validator, tag3, V, &status);
 	ck_assert_int_eq (TRUE, result);
 	ck_assert_int_eq (status.status, SUCCESS);
 
 	_status_preinit (status);
-	result = SH_Validator_register_tag (validator, tag4, &status);
+	result = SH_Validator_register_tag (validator, tag4, V, &status);
 	ck_assert_int_eq (TRUE, result);
 	ck_assert_int_eq (status.status, SUCCESS);
 
 	_status_preinit (status);
-	result = SH_Validator_register_tag (validator, tag5, &status);
+	result = SH_Validator_register_tag (validator, tag5, V, &status);
 	ck_assert_int_eq (TRUE, result);
 	ck_assert_int_eq (status.status, SUCCESS);
 
@@ -355,18 +399,20 @@ START_TEST(test_validator_tag_register_with_status)
 	{
 		sprintf (tagN, "tag%zu", validator->tag_n);
 	}
-	while (SH_Validator_register_tag (validator, tagN, NULL));
+	while (SH_Validator_register_tag (validator, tagN, V, NULL));
 
 	free (tagN);
 
 	/* test overflow */
 	_status_preinit (status);
-	result = SH_Validator_register_tag (validator, tag2, &status);
+	result = SH_Validator_register_tag (validator, tag2, V, &status);
 	ck_assert_int_eq (FALSE, result);
 	ck_assert_int_eq (E_DOMAIN, status.status);
 
 	ck_assert_int_eq (validator->tag_n, 10);
 
+	#undef V
+
 	/* cleanup */
 	/* also free garbage created for overflow test */
 	validator->tag_n = 10;
@@ -386,12 +432,14 @@ START_TEST(test_validator_tag_deregister_no_status)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
-	result = SH_Validator_register_tag (validator, tag1, NULL);
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, tag1, V, NULL);
 	ck_assert_int_eq (TRUE, result);
-	result = SH_Validator_register_tag (validator, tag2, NULL);
+	result = SH_Validator_register_tag (validator, tag2, V, NULL);
 	ck_assert_int_eq (TRUE, result);
-	result = SH_Validator_register_tag (validator, tag3, NULL);
+	result = SH_Validator_register_tag (validator, tag3, V, NULL);
 	ck_assert_int_eq (TRUE, result);
+	#undef V
 
 	result = SH_Validator_register_attr (validator, tag1, attr,
 	                                     NULL);
@@ -458,12 +506,14 @@ START_TEST(test_validator_tag_deregister_with_status)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
-	result = SH_Validator_register_tag (validator, tag1, NULL);
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, tag1, V, NULL);
 	ck_assert_int_eq (TRUE, result);
-	result = SH_Validator_register_tag (validator, tag2, NULL);
+	result = SH_Validator_register_tag (validator, tag2, V, NULL);
 	ck_assert_int_eq (TRUE, result);
-	result = SH_Validator_register_tag (validator, tag3, NULL);
+	result = SH_Validator_register_tag (validator, tag3, V, NULL);
 	ck_assert_int_eq (TRUE, result);
+	#undef V
 
 	result = SH_Validator_register_attr (validator, tag1, attr,
 	                                     NULL);
@@ -537,8 +587,10 @@ START_TEST(test_validator_tag_check)
 	validator = SH_Validator_new (NULL);
 	ck_assert_ptr_ne (NULL, validator);
 
-	result = SH_Validator_register_tag (validator, tag1, NULL);
+	#define V SH_TAG_TYPE_VOID
+	result = SH_Validator_register_tag (validator, tag1, V, NULL);
 	ck_assert_int_eq (TRUE, result);
+	#undef V
 
 	/* test */
 	result = SH_Validator_check_tag (validator, tag1);
diff --git a/todo.txt b/todo.txt
index f78312827afe3d4294bcdf7d1e435621dda0accf..c2bf52062f518850fd659fd4ef11c8b030ef5684 100644
--- a/todo.txt
+++ b/todo.txt
@@ -18,6 +18,5 @@ Fragment:
 
 Validator:
 - check for global attributes
-- add tag types
 - fix cursed behaviour, when removing fails (remove_tag_for_all_attrs)
 - initialize from file