TableHeaderScope.Column and HTML standards compliance

by chris.fulstow 6/28/2008 4:18:00 PM

Neil spotted this quirky behaviour in the TableHeaderCell control.  Suppose you've got a Table web control that renders a <table> tag with a <th scope="col">, using code something like this:

Table table = new Table()
{
    Rows =
    {
        new TableRow()
        {
            Cells =
            {
                new TableHeaderCell() { Scope = TableHeaderScope.Column, Text = "MyColumn" }
            }
        }
    }
};

Then the rendered HTML won't be W3C compliant because a scope value of "column" isn't valid:

<table border="0">
    <tr>
        <th scope="column"></th>
    </tr>
</table>

According to the W3C HTML and XHTML specs, the acceptable values for scope are [row|col|rowgroup|colgroup].  This is confirmed by the W3C Markup Validation Service, which reports the error:

XHTML validation error

Stepping into the source code for the TableHeaderCell control with Reflector or the .NET Reference Source, you can see the root of the problem:

protected override void AddAttributesToRender(HtmlTextWriter writer) {
    TableHeaderScope scope = Scope; 
    if (scope != TableHeaderScope.NotSet) {
        writer.AddAttribute(HtmlTextWriterAttribute.Scope, scope.ToString().ToLowerInvariant()); 
    }
}

When the control sets the scope attribute's value, it uses a lowercase string representation of the TableHeaderScope.Column enumeration, i.e. "column".  An enum value of TableHeaderScope.Col would've been ok, but TableHeaderScope.Column is invalid.

Workarounds

Neil has a good workaround by adding the scope attribute manually instead of using the TableHeaderCell.Scope property:

TableHeaderCell th = new TableHeaderCell();
th.Attributes["scope"] = "col";

I thought I'd have a go at extending this fix into a simple control adatper that makes sure TableHeaderCell always renders itself correctly.  It works by checking whether the Scope property is set to TableHeaderScope.Column, and if so manually adds the attribute scope="col" instead.  Here's the code:

public class TableHeaderCellAdapter : WebControlAdapter
{
    protected override void RenderBeginTag(HtmlTextWriter writer)
    {
        TableHeaderCell th = (TableHeaderCell) this.Control;
 
        if (th.Scope == TableHeaderScope.Column)
        {
            th.Scope = TableHeaderScope.NotSet;
            th.Attributes["scope"] = "col";
        }
 
        base.RenderBeginTag(writer);
    }
}

To associate the control adapter class with the TableHeaderCell control, add a browser definition file to the App_Browsers folder:

<!-- file: ~/App_Browsers/ControlAdapters.browser -->
<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter
        controlType="System.Web.UI.WebControls.TableHeaderCell"
        adapterType="TableHeaderCellAdapter"
      />
    </controlAdapters>
  </browser>
</browsers>

Tags: ,

Related posts

Comments

7/17/2008 5:24:13 PM

Neil Pullinger

Excellent idea, Chris. Thanks.

Neil Pullinger gb

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

11/21/2008 12:00:05 AM

Powered by BlogEngine.NET 1.3.0.0
Theme by Mads Kristensen

About the author

Name of author Chris Fulstow
ASP.NET Contractor, Sydney

E-mail me Send mail

Calendar

<<  November 2008  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

View posts in large calendar

Pages

    Recent comments

    Categories


    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2008

    Sign in