32

I have an HTML document where I would like to semantically group text to the head of a UL as a "header." The initial attempt looks like this:

    <ul id="databases">
        Databases:
        <li>Microsoft SQL Server - 10+ years</li>
        <li>Sybase SQL Server - 5 years</li>
        <li>Oracle - 5 years</li>
    </ul>

The W3C validator points out that there's no text allowed inside a UL, but outside a LI. I could put the text inside an LI, then use the pseudo-class :first-child to find the "header" in my CSS, but this is clearly not the semantically correct way.

How do I handle this properly?

Yes - that Jake.
  • 16,725
  • 14
  • 70
  • 96
  • 1
    Possible duplicate of [Best practice for provding a caption, title or label for a list in HTML](http://stackoverflow.com/questions/1141639/best-practice-for-provding-a-caption-title-or-label-for-a-list-in-html) – daiscog Feb 04 '16 at 10:10

8 Answers8

34

It should not be set in the first li because this would assume a sibling relationship to the succeeding li elements whereas the header is more important in the hierarchy. Imagine screen-readers etc

<h2>Databases:</h2>
<ul id="databases">        
    <li>Microsoft SQL Server - 10+ years</li>
    <li>Sybase SQL Server - 5 years</li>
    <li>Oracle - 5 years</li>
</ul>

Swap out the h2 for a h(n) depending on the hierarchy in relation to the other headers on the page. To target the header in css just give it a class if there are other headers that will share the same style e.g.

<h2 class="subHeader">Languages:</h2>
<ul id="languages">        
    <li>English</li>
    <li>Chinese</li>
    <li>French</li>
</ul>

Otherwise give it an id

Hashim Aziz
  • 4,074
  • 5
  • 38
  • 68
Nick Allen
  • 11,970
  • 11
  • 45
  • 58
27

Just for reference, HTML 3.0 had <lh>:

<ul>
    <lh>This is a list header!
    <li>Item A
    <li>Item B
    <li>Item C
</ul>
Pup
  • 10,236
  • 6
  • 45
  • 66
  • 19
    Sadly this element was dropped. http://www.w3.org/TR/2014/CR-html5-20140429/grouping-content.html#the-li-element – George May 14 '14 at 18:55
  • Interesting, this tells me I'm using HTML wrong for having columns (where one might wish for a repeating header after a break) or generating PDF:s etc (with a similar use case)... or maybe they just didn't consider breaks... – Erk Feb 24 '23 at 22:13
15

You could try the <dl> (description list) tag for your listing purposes. You get a much cleaner code.

<dl>
  <dt>Databases</dt>
   <dd>Microsoft SQL Server - 10+ years</dd>
   <dd>Sybase SQL Server - 5 years</dd>
   <dd>Oracle - 5 years</dd>
  <dt>Second heading</dt>
   <dd>Item 1</dd>
   <dd>Item 2</dd>
   <dd>Item 3</dd>
</dl>

More information on description list here http://www.w3schools.com/tags/tag_dl.asp

Alireza Rezaee
  • 314
  • 3
  • 10
Nima Foladi
  • 364
  • 3
  • 4
  • Is it good for contact info? For example
    Phone numbers
    x-xxx-xxx...
    ? I mean is it correct from the search bots or indexers point of view. Wouldn't it bad for SEO? Or may be classical
      is just more proper tag for usual information list like contacts or company's staff list?
    – remort Jan 09 '13 at 17:20
  • You might want to have a look at hcard microformats for contact info: http://microformats.org/wiki/hcard – Jeff S. Nov 28 '13 at 05:16
  • @remort: `dt`/`dd` is *perfect* for contact information. – Bergi Mar 09 '16 at 18:35
7
<section>
    <h1>Databases:<h1>
    <ul>
        <li>Microsoft SQL Server - 10+ years</li>
        <li>Sybase SQL Server - 5 years</li>
        <li>Oracle - 5 years</li>
    </ul>
</section>

or even better

<section>
    <h1>Databases:</h1>
    <dl>
        <dt>Microsoft SQL Server</dt> <dd>10+ years</dd>
        <dt>Sybase SQL Server</dt>    <dd>5 years</dd>
        <dt>Oracle</dt>               <dd>5 years</dd>
    </dl>
</section>

Note the h1 is confined to the section, so it's not ambiguous as to whether the content following the list belongs to the heading Databases. In other words, the heading is scoped within the section.

chharvey
  • 8,580
  • 9
  • 56
  • 95
3

here's an alternate answer:

<ul id="databases">
        <li style="list-style:none"><strong>Databases:</strong></li>
        <li>Microsoft SQL Server - 10+ years</li>
        <li>Sybase SQL Server - 5 years</li>
        <li>Oracle - 5 years</li>
    </ul>

the advantage of this is that you can use several of these "headers" within your UL without breaking them up into separate UL's and the default white space that causes (or using CSS to eliminate the white space...)

fbas
  • 1,676
  • 3
  • 16
  • 26
  • 1
    It works, but if you're using ordered list, you will also have to add the start property to ol tag(and usually set to 0 instead of the default 1). – Silviu Burcea Dec 19 '13 at 13:00
2

Or nest your lists like so

<ul>
    <li>Databases</li>
    <li>
        <ul>
            <li>Microsoft SQL Server - 10+ years</li>
            <li>Sybase SQL Server - 5 years</li>
            <li>Oracle - 5 years</li>
        </ul>
    </li>
</ul>
jackbot
  • 2,931
  • 3
  • 27
  • 35
1

As per my answer to this question, I find the HTML5 figure and figcaption elements most appropriate:

<figure>
    <figcaption>Databases</figcaption>
    <ul>
        <li>Microsoft SQL Server - 10+ years</li>
        <li>Sybase SQL Server - 5 years</li>
        <li>Oracle - 5 years</li>
    </ul>
</figure>

Or alternatively CSS3's ::before pseudo-element can be a nice solution:

HTML:

<ul title="Fruit">
    <li>Apple</li>
    <li>Pear</li>
    <li>Orange</li>
</ul>

CSS:

ul[title]::before {
    content: attr(title);
    /* then add some nice styling as needed, eg: */
    display: block;
    font-weight: bold;
    padding: 4px;
}
daiscog
  • 11,441
  • 6
  • 50
  • 62
  • 1
    This is acceptable, but just be aware that `
    ` elements do not add to the document outline. Therefore, figures and figcaptions will be skipped when users / assistive technology jump from section to section or from heading to heading.
    – chharvey Jan 11 '19 at 22:08
-1

Maybe something like this:

<div>
 <span>Databases:<span>
 <ul id="databases">
        <li>Microsoft SQL Server - 10+ years</li>
        <li>Sybase SQL Server - 5 years</li>
        <li>Oracle - 5 years</li>
 </ul>
 </div>
Roman
  • 64,384
  • 92
  • 238
  • 332