diff --git a/_test/tests/inc/parser/renderer_xhtml.test.php b/_test/tests/inc/parser/renderer_xhtml.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..d99eac1025b03285ef65cc86e3ef386ead6e366c
--- /dev/null
+++ b/_test/tests/inc/parser/renderer_xhtml.test.php
@@ -0,0 +1,244 @@
+<?php
+
+/**
+ * Class renderer_xhtml_test
+ */
+class renderer_xhtml_test extends DokuWikiTest {
+    /** @var Doku_Renderer_xhtml */
+    protected $R;
+
+    /**
+     * Called for each test
+     *
+     * @throws Exception
+     */
+    function setUp() {
+        parent::setUp();
+        $this->R = new Doku_Renderer_xhtml();
+    }
+
+    function tearDown() {
+        unset($this->R);
+    }
+
+    function test_tableopen_0arg() {
+        $this->R->table_open();
+
+        $expected = '<div class="table"><table class="inline">'."\n";
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_tableopen_1arg() {
+        $this->R->table_open(4);
+
+        $expected = '<div class="table"><table class="inline">'."\n";
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_tableopen_2arg() {
+        $this->R->table_open(4, 4);
+
+        $expected = '<div class="table"><table class="inline">'."\n";
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_tableopen_3arg() {
+        $this->R->table_open(4, 4, 100);
+
+        $expected = '<div class="table sectionedit1"><table class="inline">'."\n";
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_tableopen_4arg() {
+        $this->R->table_open(4, 4, 100, 'feature');
+
+        $expected = '<div class="table feature sectionedit1"><table class="inline">'."\n";
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_table() {
+        $this->R->table_open(null, null, null, 'feature');
+        $this->R->tablethead_open();
+
+        $this->R->tablerow_open('item');
+        $this->R->tableheader_open();
+        $this->R->cdata('header1');
+        $this->R->tableheader_close();
+        $this->R->tableheader_open(1, null, 1, 'second');
+        $this->R->cdata('header2');
+        $this->R->tableheader_close();
+        $this->R->tablerow_close();
+
+        $this->R->tablethead_close();
+        $this->R->tabletbody_open();
+
+        $this->R->tablerow_open('values');
+        $this->R->tablecell_open(1, null, 1, 'first value');
+        $this->R->cdata('cell1,1');
+        $this->R->tablecell_close();
+        $this->R->tablecell_open(1, null, 1, 'second');
+        $this->R->cdata('cell1,2');
+        $this->R->tablecell_close();
+        $this->R->tablerow_close();
+
+        $this->R->tablerow_open();
+        $this->R->tablecell_open();
+        $this->R->cdata('cell2.1');
+        $this->R->tablecell_close();
+        $this->R->tablecell_open();
+        $this->R->cdata('cell2,2');
+        $this->R->tablecell_close();
+        $this->R->tablerow_close();
+
+        $this->R->tabletbody_close();
+        $this->R->table_close();
+
+        $expected = '<div class="table feature"><table class="inline">
+	<thead>
+	<tr class="row0 item">
+		<th class="col0">header1</th><th class="col1 second">header2</th>
+	</tr>
+	</thead>
+	<tbody>
+	<tr class="row1 values">
+		<td class="col0 first value">cell1,1</td><td class="col1 second">cell1,2</td>
+	</tr>
+	<tr class="row2">
+		<td class="col0">cell2.1</td><td class="col1">cell2,2</td>
+	</tr>
+	</tbody>
+</table></div>
+';
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_olist() {
+        $this->R->document_start();
+        $this->R->listo_open();
+
+        $this->R->listitem_open(1, Doku_Handler_List::NODE);
+        $this->R->listcontent_open();
+        $this->R->cdata('item1');
+        $this->R->listcontent_close();
+
+        $this->R->listo_open();
+
+        $this->R->listitem_open(2);
+        $this->R->listcontent_open();
+        $this->R->cdata('item1b');
+        $this->R->listcontent_close();
+        $this->R->listitem_close();
+
+        $this->R->listo_close();
+        $this->R->listitem_close();
+
+        $this->R->listitem_open(1);
+        $this->R->listcontent_open();
+        $this->R->cdata('item2');
+        $this->R->listcontent_close();
+        $this->R->listitem_close();
+
+        $this->R->listitem_open(1, Doku_Handler_List::NODE);
+        $this->R->listcontent_open();
+        $this->R->cdata('item3');
+        $this->R->listcontent_close();
+
+        $this->R->listo_open('special');
+
+        $this->R->listitem_open(2);
+        $this->R->listcontent_open();
+        $this->R->cdata('item3b');
+        $this->R->listcontent_close();
+        $this->R->listitem_close();
+
+        $this->R->listo_close();
+        $this->R->listitem_close();
+
+        $this->R->listo_close();
+        $this->R->document_end();
+
+        $expected = '<ol>
+<li class="level1 node"><div class="li">item1</div>
+<ol>
+<li class="level2"><div class="li">item1b</div>
+</li>
+</ol>
+</li>
+<li class="level1"><div class="li">item2</div>
+</li>
+<li class="level1 node"><div class="li">item3</div>
+<ol class="special">
+<li class="level2"><div class="li">item3b</div>
+</li>
+</ol>
+</li>
+</ol>
+';
+        $this->assertEquals($expected, $this->R->doc);
+    }
+
+    function test_ulist() {
+        $this->R->document_start();
+        $this->R->listu_open();
+
+        $this->R->listitem_open(1, Doku_Handler_List::NODE);
+        $this->R->listcontent_open();
+        $this->R->cdata('item1');
+        $this->R->listcontent_close();
+
+        $this->R->listu_open();
+
+        $this->R->listitem_open(2);
+        $this->R->listcontent_open();
+        $this->R->cdata('item1b');
+        $this->R->listcontent_close();
+        $this->R->listitem_close();
+
+        $this->R->listu_close();
+        $this->R->listitem_close();
+
+        $this->R->listitem_open(1);
+        $this->R->listcontent_open();
+        $this->R->cdata('item2');
+        $this->R->listcontent_close();
+        $this->R->listitem_close();
+
+        $this->R->listitem_open(1, Doku_Handler_List::NODE);
+        $this->R->listcontent_open();
+        $this->R->cdata('item3');
+        $this->R->listcontent_close();
+
+        $this->R->listu_open('special');
+
+        $this->R->listitem_open(2);
+        $this->R->listcontent_open();
+        $this->R->cdata('item3b');
+        $this->R->listcontent_close();
+        $this->R->listitem_close();
+
+        $this->R->listu_close();
+        $this->R->listitem_close();
+
+        $this->R->listu_close();
+        $this->R->document_end();
+
+        $expected = '<ul>
+<li class="level1 node"><div class="li">item1</div>
+<ul>
+<li class="level2"><div class="li">item1b</div>
+</li>
+</ul>
+</li>
+<li class="level1"><div class="li">item2</div>
+</li>
+<li class="level1 node"><div class="li">item3</div>
+<ul class="special">
+<li class="level2"><div class="li">item3b</div>
+</li>
+</ul>
+</li>
+</ul>
+';
+        $this->assertEquals($expected, $this->R->doc);
+    }
+}
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 236409b45ae31bead8f32fa2d36fc99214f31b25..0f3d814e66a5dead7c02750befa89a959c1a8e49 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -427,9 +427,15 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
     /**
      * Open an unordered list
+     *
+     * @param string $classes css class
      */
-    function listu_open() {
-        $this->doc .= '<ul>'.DOKU_LF;
+    function listu_open($classes = null) {
+        $class = '';
+        if($classes !== null) {
+            $class = " class=\"$classes\"";
+        }
+        $this->doc .= "<ul$class>".DOKU_LF;
     }
 
     /**
@@ -441,9 +447,15 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
     /**
      * Open an ordered list
+     *
+     * @param string $classes css class
      */
-    function listo_open() {
-        $this->doc .= '<ol>'.DOKU_LF;
+    function listo_open($classes = null) {
+        $class = '';
+        if($classes !== null) {
+            $class = " class=\"$classes\"";
+        }
+        $this->doc .= "<ol$class>".DOKU_LF;
     }
 
     /**
@@ -763,6 +775,8 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      *
      * @param string $link       The link name
      * @param bool   $returnonly whether to return html or write to doc attribute
+     * @return void|string writes to doc attribute or returns html depends on $returnonly
+     *
      * @see http://en.wikipedia.org/wiki/CamelCase
      */
     function camelcaselink($link, $returnonly = false) {
@@ -779,6 +793,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string $hash       hash link identifier
      * @param string $name       name for the link
      * @param bool   $returnonly whether to return html or write to doc attribute
+     * @return void|string writes to doc attribute or returns html depends on $returnonly
      */
     function locallink($hash, $name = null, $returnonly = false) {
         global $ID;
@@ -900,6 +915,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string       $url        full URL with scheme
      * @param string|array $name       name for the link, array for media file
      * @param bool         $returnonly whether to return html or write to doc attribute
+     * @return void|string writes to doc attribute or returns html depends on $returnonly
      */
     function externallink($url, $name = null, $returnonly = false) {
         global $conf;
@@ -963,6 +979,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string       $wikiName   indentifier (shortcut) for the remote wiki
      * @param string       $wikiUri    the fragment parsed from the original link
      * @param bool         $returnonly whether to return html or write to doc attribute
+     * @return void|string writes to doc attribute or returns html depends on $returnonly
      */
     function interwikilink($match, $name = null, $wikiName, $wikiUri, $returnonly = false) {
         global $conf;
@@ -1017,6 +1034,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string       $url        the link
      * @param string|array $name       name for the link, array for media file
      * @param bool         $returnonly whether to return html or write to doc attribute
+     * @return void|string writes to doc attribute or returns html depends on $returnonly
      */
     function windowssharelink($url, $name = null, $returnonly = false) {
         global $conf;
@@ -1056,6 +1074,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string       $address    Email-Address
      * @param string|array $name       name for the link, array for media file
      * @param bool         $returnonly whether to return html or write to doc attribute
+     * @return void|string writes to doc attribute or returns html depends on $returnonly
      */
     function emaillink($address, $name = null, $returnonly = false) {
         global $conf;
@@ -1107,7 +1126,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string $cache     cache|recache|nocache
      * @param string $linking   linkonly|detail|nolink
      * @param bool   $return    return HTML instead of adding to $doc
-     * @return void|string
+     * @return void|string writes to doc attribute or returns html depends on $return
      */
     function internalmedia($src, $title = null, $align = null, $width = null,
                            $height = null, $cache = null, $linking = null, $return = false) {
@@ -1161,6 +1180,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param string $cache   cache|recache|nocache
      * @param string $linking linkonly|detail|nolink
      * @param bool   $return  return HTML instead of adding to $doc
+     * @return void|string writes to doc attribute or returns html depends on $return
      */
     function externalmedia($src, $title = null, $align = null, $width = null,
                            $height = null, $cache = null, $linking = null, $return = false) {
@@ -1199,6 +1219,9 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     /**
      * Renders an RSS feed
      *
+     * @param string $url    URL of the feed
+     * @param array  $params Finetuning of the output
+     *
      * @author Andreas Gohr <andi@splitbrain.org>
      */
     function rss($url, $params) {
@@ -1290,12 +1313,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      *
      * @param int $maxcols maximum number of columns
      * @param int $numrows NOT IMPLEMENTED
-     * @param int $pos     byte position in the original source
+     * @param int $pos byte position in the original source
+     * @param string $classes css class
      */
-    function table_open($maxcols = null, $numrows = null, $pos = null) {
+    function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) {
         // initialize the row counter used for classes
         $this->_counter['row_counter'] = 0;
         $class                         = 'table';
+        if($classes !== null) {
+            $class .= ' ' . $classes;
+        }
         if($pos !== null) {
             $class .= ' '.$this->startSectionEdit($pos, 'table');
         }
@@ -1345,11 +1372,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
     /**
      * Open a table row
+     *
+     * @param string $classes css class
      */
-    function tablerow_open() {
+    function tablerow_open($classes = null) {
         // initialize the cell counter used for classes
         $this->_counter['cell_counter'] = 0;
         $class                          = 'row'.$this->_counter['row_counter']++;
+        if($classes !== null) {
+            $class .= ' ' . $classes;
+        }
         $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB;
     }
 
@@ -1366,12 +1398,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      * @param int    $colspan
      * @param string $align left|center|right
      * @param int    $rowspan
+     * @param string $classes css class
      */
-    function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
+    function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
         $class = 'class="col'.$this->_counter['cell_counter']++;
         if(!is_null($align)) {
             $class .= ' '.$align.'align';
         }
+        if($classes !== null) {
+            $class .= ' ' . $classes;
+        }
         $class .= '"';
         $this->doc .= '<th '.$class;
         if($colspan > 1) {
@@ -1394,15 +1430,19 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
     /**
      * Open a table cell
      *
-     * @param int    $colspan
-     * @param string $align left|center|right
-     * @param int    $rowspan
+     * @param int       $colspan
+     * @param string    $align left|center|right
+     * @param int       $rowspan
+     * @param string    $classes css class
      */
-    function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
+    function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) {
         $class = 'class="col'.$this->_counter['cell_counter']++;
         if(!is_null($align)) {
             $class .= ' '.$align.'align';
         }
+        if($classes !== null) {
+            $class .= ' ' . $classes;
+        }
         $class .= '"';
         $this->doc .= '<td '.$class;
         if($colspan > 1) {
@@ -1429,6 +1469,9 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
      *
      * Assembles all parts defined in $link returns HTML for the link
      *
+     * @param array $link attributes of a link
+     * @return string
+     *
      * @author Andreas Gohr <andi@splitbrain.org>
      */
     function _formatLink($link) {