
Forms can be complicated. Here are a few guidelines to take the pain away.
- Use fieldsets to group sections of forms and related inputs
- Use tables to group labels, inputs, and help. Using tables to lay out forms isn’t the best, in terms of semantic markup, but we’re making a slight compromise here to ease development.
<form id="oc-join-form" name="edit_form" method="post" enctype="multipart/form-data" action="/portal_memberdata/portal_factory/OpenMember/openmember.2007-05-08.0523490218/reg_form">
<fieldset>
<legend class="headingBlock">
<h1>Join OpenPlans</h1>
<p class="oc-headingContext">Registration is free and your email will not be
shared with anyone, however, you will need to confirm your email address in order to avoid
spam bots abusing this system
</p>
</legend>
<table class="oc-form">
<tbody>
<tr class="oc-form-row">
<th scope="row" class="oc-form-label">
<label for="">Username</label>
</th>
<td class="oc-form-value">
<input type="text" name="__ac_name" id="__ac_name" />
</td>
<td class="oc-form-help">
<span class="oc-form-context">
Pick something funny
</span>
<span id="oc-username-validator" class="oc-form-validator">
Sorry, that username is taken
</span>
</td>
</tr>
<tr class="oc-form-row">
<th scope="row" class="oc-form-label">
<label for="">Full Name</label>
</th>
<td class="oc-form-value">
<input type="text" />
</td>
<td class="oc-form-help">
<span class="oc-form-context">
(optional)
</span>
<span class="oc-form-validator">
</span>
</td>
</tr>
</tbody>
</table>
</fieldset>
</form>
This markup will make the following naked html:

Add CSS, and you get the finished product:


Not your daddy’s Deliverance.
Since our markup and CSS will need to be ported into other people’s sites via Deliverance, we’ll add an oc- namespace to all our classes and IDs (in addition to following our other naming rules). This will avoid any conflicts with styles in the parent site. For example:
<div class="oc-wiki">
<div class="oc-headingBlockâ€>
<h2>Project Home</h2>
</div><!– end .oc-headingBlock –>
<ul class=â€oc-tabsâ€>
<li>
<a href=â€â€ rel=â€viewâ€>view</a>
</li>
<li class=â€oc-selectedâ€>
<a href=â€â€ rel=â€editâ€>edit</a>
</li>
<li>
<a href=â€â€ rel=â€historyâ€>history</a>
</li>
</ul><!– end .oc-tabs –>
<!–- more stuff here -–>
</div><!–- end .oc-wiki –->

Class naming conventions
Hierarchical classes:
Hierarchical elements take class names from their parents, within reason. The idea is to keep it consistent while avoiding 10-part class names. Use your best judgement here.
<div class="oc-widget oc-widget-feed">
<h2>Recently updated projects</h2>
<ul class="oc-widget-feed-list">
<li class="oc-feed-item oc-clearAfter" tal:repeat="project view/recentprojects">
<img class="oc-avatar" src="" tal:attributes="src project/image_src | nothing" />
<h3 class="oc-feed-item-title">
<a href="" tal:attributes="href project/absolute_url" tal:content="nocall: project/title">Project Title</a>
</h3>
<p class="oc-feed-item-data oc-discreetText" tal:define="nmembers python: len(project.projectMemberIds())">
<span tal:replace="nmembers">YY</span> member<span tal:condition="python: nmembers > 1" tal:replace="string:s" />, active since <span tal:replace="python: view.create_date(project)">Jan 1937</span>
</p>
<p class="oc-feed-item-description" tal:content="project/mission | string: project mission statement goes here">
This is the descriptive text for a project. Apparently it doesn’t quite work right yet. Is there even a field for users to fill out or entry to call from a database?
</p>
</li>
</ul><!– end .oc-widget-feed-list –>
</div><!– end .oc-widget-feed –>
Reusable/generic classes:
Reusable / generic classes can go anywhere, without specifying anything more. For example, an oc-headingBlock can go inside any block-level element, including “widgets”.
<div class="oc-headingBlock">
<h1>Projects on OpenPlans</h1>
<p class="oc-headingContext">Currently serving <span tal:replace="view/nprojects"/> projects</p>
</div><!-- end .oc-headingBlock -->
Two-class naming structure for generics.
First class name defines generic. Second enables customizations.
<div class="oc-widget oc-widget-feed">
<!– some stuff –>
</div><!– end .oc-widget.oc-widget-feed –>
Case studies:
A few code examples here… (simple to complex)
- Feed
- Wiki
- Forms

Simple, semantic, reusable markup, tied to organized CSS.
- Simple: Keep class names as simple as possible while using The OC and sticking with our naming conventions.
- Semantic: Use <h1>, <h2>, etc. for headings, <ul> for unordered lists, <ol> for ordered lists, etc. Use generic <div>s & <span>s as little as possible. (Almost) never use tables for layout.
- Reusable: Find patterns and use existing markup whenever possible. Keep developers out of the CSS file as much as possible.
Welcome to 23 screens, and welcome to the beginning of a magical journey through the wonderful world of web design.
23 screens is our attempt to document the process of rebuilding our web application, OpenPlans, from the ground up—one screen at a time. Along the way, we’ll explore all the various goals & constraints that shape our design decisions.
The goal is simple: build 23 screens in 10 days, using (X)HTML, CSS, and a bit of Javascript, so that they can be made functional by an eagerly waiting team of developers. We’re hoping that this blog will help us keep things straight, and might occasionally prove itself interesting to others out there on the interweb.
So, buckle up, hold your hats, and let’s go!