With RichFaces you can create a data table like this:
<rich:dataTable id="myTable" value="#{myBean.values}" var="value">
<f:facet name="header">
<rich:columnGroup>
<rich:column />
<rich:column>Value 1</rich:column>
<rich:column>Value 2</rich:column>
<rich:column>Value 3</rich:column>
<rich:column>Value 4</rich:column>
</rich:columnGroup>
</f:facet>
<rich:column />
<rich:column>#{value.val1}</rich:column>
<rich:column>#{value.val2}</rich:column>
<rich:column>#{value.val3}</rich:column>
<rich:column>#{value.val4}</rich:column>
<f:facet name="footer">
<rich:columnGroup>
<rich:column>TOTALS</rich:column>
<rich:column>#{myBean.totalVal1}</rich:column>
<rich:column>#{myBean.totalVal2}</rich:column>
<rich:column>#{myBean.totalVal3}</rich:column>
<rich:column>#{myBean.totalVal4}</rich:column>
</rich:columnGroup>
</f:facet>
</rich:dataTable>
This generates a basic HTML <table> with five columns, a header, and a footer.
However, if you do this instead (the <rich:dataTable> is exactly the same):
<div id="myTableHeader"></div>
<div id="myTableBody">
<rich:dataTable id="myTable" value="#{myBean.values}" var="value">
<f:facet name="header">
<rich:columnGroup>
<rich:column />
<rich:column>Value 1</rich:column>
<rich:column>Value 2</rich:column>
<rich:column>Value 3</rich:column>
<rich:column>Value 4</rich:column>
</rich:columnGroup>
</f:facet>
<rich:column />
<rich:column>#{value.val1}</rich:column>
<rich:column>#{value.val2}</rich:column>
<rich:column>#{value.val3}</rich:column>
<rich:column>#{value.val4}</rich:column>
<f:facet name="footer">
<rich:columnGroup>
<rich:column>TOTALS</rich:column>
<rich:column>#{myBean.totalVal1}</rich:column>
<rich:column>#{myBean.totalVal2}</rich:column>
<rich:column>#{myBean.totalVal3}</rich:column>
<rich:column>#{myBean.totalVal4}</rich:column>
</rich:columnGroup>
</f:facet>
</rich:dataTable>
</div>
<div id="myTableFooter"></div>
RichFaces will place the <thead> inside the "myTableHeader" <div> and the <tfoot> inside the "myTableFooter" <div>, with the <tbody> remaining inside the <table> in the "myTableBody" <div>. RichFaces sets the width of every cell so that the columns still line up. Note that the ID's of these elements are important - they must start with the ID of the table element and end with these specific suffixes. The <table> actually contains a display:none copy of the header as well, and an empty footer.
I only know this works because I found it in some of our code, but I haven't been able to find any documentation on this feature. Is this feature documented anywhere? I don't really know what the rules are for it.