Views 2 Theming Documentation

You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

This is an effort to get people in the community to do some work for me. Maybe I'm a bit lazy, but this is a piece of work that I've admitted I'm simply never going to get to. Yet it is needed.

This document is intended to be a comprehensive document on theming Views. It should cover all of the basics, and it should also include tutorials. It really needs to be both.

I want to start with a topic list. I'm not even sure the best way to lay this out, so I'm going to start with the really obvious topics:

This is a WIKI page. I welcome people to edit this document. Ideally, once parts of this document are ready they can be moved to, but this is an excellent place to work from.

How Views are themed, in general
How to theme a basic view
How to theme a single field for a view
How to write a Views plugin


The term "Views Theming" covers a range of activities around formatting Views output. These include:

The Views output contains a rich set of div tags allowing fine-grained CSS control over the output.
List View Item Formatting
With example code provided by the Views Theme Wizard a PHP template file can be used to format the output of a list view.
Node/Teaser View Formatting
The Node and Teaser View types use the "native" formatting of the nodes being displayed. Data in these views are themed via the node templates of the nodes being displayed. e.g., node.tpl.php

Theme Views 2 from template files

Get any field value in individual field template file:

// current row field value. Combined field name could be changed by many factors
$row_value = $row['COMBINED_FIELD_ID']

// current row field value
$row_value = $row->{$view->field['FIELD_ID']->field_alias};

// current rendered field value (with prefix, suffix et.)
$rendered_value = $view->field['FIELD_ID']->render($row);

Default views list output

Views outputs list views as a series of divs and an unordered list. These allow you to use css selectors to target all views and fields on your site, or just the specific views and fields in the specific view you're working on. It's possible to quite radically alter how list views appear just by carefully targeting css at the various elements.

For the purposes of this example, we'll use a list view called "example_list" using the following fields, and assuming it's displaying as a page:

Image (from imagefield/cck, we'll call our image field "field_photo")
node title (as link)

Viewing the page source of your view will show the structure of your view, it begins with:

<div class="view view-example-list">

This gives you the css selectors .view and .view-example-list. Applying styles to .view will affect all views site-wide, applying styles to .view-example-list affects just our example_list view. Just about every div in a list view contains two classes in this format - one for every view (or field), and one for the specific view or field you're working with.

If your view has a header, the next thing you'll see is:

<div class="view-header view-header-example-list">

.view-header will select every header in every view, .view-header-example-list will... hopefully you get that bit by now.

Then we get to:

<div class="view-content view-content-example-list">

which follows the same format.

Within view-content we get the list itself. It's at this point where the fields you selected when creating the view actually get output in an unordered list. The unordered list, the entire result set, and each individual field all get wrapped in divs for easy css selection.

In our example, all of this code appears just before the <img> tag.

<div class="item-list"><ul><li><div class='view-item view-item-example-list'><div class='view-field view-data-node-data-field-photo-field-photo-fid'>

Looks confusing doesn't it? Well it's not so bad.

.item-list wraps the unordered list, this allows any styles for .item-list in your theme to be overridden by .view .item-list

Then an unordered list wraps all the results, with each row (usually node) appearing as a list item (within one set of <li></li> tags.)

Often, you'll want to remove bullet points from unordered lists in views, you can do this using:

.view-example-list ul li {
  list-style-image: none;
  list-style-type: none;

Each row of results also gets enclosed in a div as well as the unordered list:

<div class='view-item view-item-example-list'>

At this point, we get to the very first field output by your view, since field_photo was at the top of our field selection, it gets printed first:

<div class='view-field view-data-node-data-field-photo-field-photo-fid'>

At this point views stops outputting classes for .all-views .your-view, and switches to .all-fields .your-field. This allows you to define the behaviour of fields across a number of different views, for example floating an imagefield left in any list view on your site.

To do this, we could use

.view-data-node-data-field-photo-field-photo-fid img {
float: left;

Or to float the image left in our example view, but leave it unaffected everywhere else, we could use:
.view-example-list .view-data-node-data-field-photo-field-photo-fid img

or just

.view-example-list img

if there's just the one image field.

The next set of code is for the node title:
<div class='view-field view-data-node-title'>
Note that .view-field is repeated, applying to any field of whatever type, and that .view-data-node-title applies to all instances of node-title.

By now, you should have an understanding of what each set of divs represents, and how to target css at individual fields.

If you want to theme your page view one way, and blocks slightly differently, you can add .block to any of the above selectors (i.e. .block .view .item-list) assuming your block.tpl.php uses <div class="block"></div> to wrap blocks.


OK I added a blow by blow of

catch's picture

OK I added a blow by blow of the first half of a basic list view. I reckon a lot of people starting with views will just get confused by all the divs and classes first time they look at the generated html, I know I did, so this guide should probably start with those to avoid too many wtf? moments. If you can't deal with applying divs and classes and css, you shouldn't be messing with phptemplate to change them.

It's quick and nasty, but it's a start.

I recently wrote this on

joachim's picture

I recently wrote this on style plugins for Views 1:
How much of that is changing for Views 2?

Is there any documentation

joachim's picture

Is there any documentation on writing new style plugins yet?

There's a good start, at least!

TravisCarden's picture

I was looking for the same thing, joachim. I found "Writing Views 2 style and row plugins" at Starting Views2 Documentation. (I'm gonna try to write an Mp3 (M3u) Playlist style plugin.) Hope it helps!

Would this wiki be aimed

bb_matt's picture

Would this wiki be aimed squarely at "out of the box" drupal templates?

I ask, simply because in some circumstances, modification of the templates can create a situation where the drupal CSS methods aren't used at all?

I'm not a massive fan of the way that drupal uses CSS, if only because, by it's very nature, Drupal has to be a "one size fits all" platform.

I very much understand this, so don't get me wrong with my concerns below!

When you start getting markup like this:-

<div class='view view-departments'><div class='view-header view-header-departments'><p>text</p>
<div class='view-content view-content-departments'><div id="node-122" class="node node-content">
    <h2 class="title"><a href="#" title="text">text</a></h2>

    <div class="date">13 December 2007 - 3:40pm</div>
  <div class="content"><p>Design and Technology at Churchmead</p>

I start getting very concerned as a markup purist.
Lets face it, the above code requires at maximum, two div areas for styling and you could probably get away with one.

It's very messy to be honest.

My point is, an approach to styling views could be very different if the templates have been modified in such a way, that the amount of markup is drastically reduced.

My personal point of view is

merlinofchaos's picture

My personal point of view is that a dynamic content system is a nightmare for markup purists; if you're a markup purist, Drupal must be hell for you, but that's the way it is. Views' markup is designed to be as easy to CSS as possible. Views almost certainly contains too much markup for any given purpose but in the past I have gone through and shown why all markup is actually needed for the kind of flexibility that is needed.

This documentation should be aimed less at the markup purist and more at the general Drupal user type. That said, a markup purist ought to be able to use this documentation to re-theme his or her views to create 'cleaner' markup.

That said, my feeling is that markup purism has no place in a content management system. Markup needs to be created to be clean, elegant and usable. Purists want markup to be simple and semantic but by their nature, a dynamic system cannot be.

Yes, I can totally relate to

bb_matt's picture

Yes, I can totally relate to that. No, Drupal isn't hell from a 'purist' perspective - I can close my eyes and ignore that - heh :)
It has been hell from a "How the heck?" or "Why?" (bursts into tears and hammers the desk with fists)

Thinking about this some more, the layout code has obviously been specifically designed to allow for almost any styling eventuality.
Pretty much every tag will have a class and/or id.

Perhaps 'purist' is too fine a point, but I do like to keep markup as lean and mean as possible.

A dynamic system can be simple and semantic, but only if it's geared toward a single theme or a specific project.

Back onto the topic you started, I would definately explain the CSS cascade concept and encourage themers to use it as much as possible, as used correctly, it gives you an extra level of control. For instance, you may have a class or id on your body tag (minor template tweak) which could enable you to completely change the same view for a different site section.

Tags that don't have a class

merlinofchaos's picture

Tags that don't have a class are very difficult in cascades because they're extremely difficult to identify. Also, cascading is nice until you try to put one construct inside another; then suddenly cascading turns into this Thing You Do Not Want as construct A, which is inside B, picks up all the markup from B and then from A and the browser tries to merge them in a way that almost always fails. While this is more true for Panels than it is for Views, there are cases where you'll have a view within a view. Or something that isn't a view within a view. And at that point, it's really important to have a class to identify what you're styling...and what you're not styling.

Yes, absolutely, but I was

bb_matt's picture

Yes, absolutely, but I was refering more to a situation where you DO actually specify the classes in the cascade.


<div class="block block-views" id="block-views-did_you_know">
    <h2 class="title">Did you know</h2>
    <div class="content">
       <div class='view view-did-you-know'><div class='view-content view-content-did-you-know'>       
           <div class="node">
             <p>For special offers on books, join the Mailing List and be the first to hear.  Click on <a href=""></a></p>

In this case, assume we have a right column block view and in the Bookshop section, we want the block background to be Green, but in the Library section, it should be yellow. All other areas should default to white.

To do this, we've set our page template up to include an ID based on $content_class (a fairly common trick)

#main .sidebar-right  .block.block-views .block-views-did_you_know {
   border:2px solid #ccc;

body#bookshop #main .sidebar-right .block.block-views .block-views-did_you_know {

body#library #main .sidebar-right .block.block-views .block-views-did_you_know {

I have been a bit excessive with the cascade, you could easily drop #main, .block, and .block-views.

We could take another example and assume we haven't changed the ID of body at all. What we want to do here is to have a default set of styles for ALL of our block views in both a left and right column, with the exception of a block 'did-you-know', sitting in the right sidebar , which we want to have a green background.

#main .sidebar-right .block.block-views, #main .sidebar-left .block.block-views {
   border:1px solid #000;

#main .sidebar-right .block.block-views .block-views-did_you_know {

Possibly all of this is a little obvious to most, but can really assist in adding that extra 'edge' to your styling.
It also cuts out a lot of potentially redundant code.

Comment cleaning; please stay on-topic

merlinofchaos's picture

I have started aggressively deleting off-topic comments on this thread. If you posted a comment here and it's gone, that is why.

Handbook page

rootwork's picture

At the Drupalcon doc sprint this morning, I worked on the Views 2 theming handbook page and basically rewrote it from the ground up. I also incorporated several things in the comments and from linked tutorials (and comments in those tutorials).

I actually didn't know about this page and I'm just running across it now. Take a look at how I laid things out and feel free to alter them or start to integrate stuff from above, though I see there hasn't been much activity lately. In any case, I apologize if I got ahead or went in the wrong direction with this handbook page.

Apart from modifying the content of that page, I think ultimately it should probably be broken into several child pages, somewhat along the lines of the steps I laid out (unless they're completely unintelligible or something). This is particularly true for the section on template variables. I wanted to get all of the info up there first, but we can start working on breaking it up into separate child pages now as well.

Let me know what you think. Chasten me if you must. :)

Please note that the biggest

merlinofchaos's picture

Please note that the biggest issue here is that the official views 2 documentation is part of the advanced help that ships with Views. I didn't even know about this page, and I don't check this stuff for accuracy. I'm not sure I like having good documentation in 2 places; I'd much rather have all of the good bits that I don't have in the advanced help and then this page should really just be a pointer to that.