Introduction
WSJ Admin Tools Style Guide
This style guide aims to baseline all WSJ tools styles. Our web apps have been rife with inconsistencies. The goal of this page and the included materials is to put an end to that.
To view the markup of a component, click the icon.
Structure
Markup Structure
The page should be constructed as follows: n number of section elements are housed within a main element. The header will be a sibling of main, and everything aforementioned is housed within the body.
The main element in centered hoizontally on the page with 40px of margin on the top and bottom. Each section has a 40px margin-bottom, spacing out the content nicely.
<body>
<header>...</header>
<main>
<section>...</section>
<section>...</section>
<section>...</section>
</main>
</body>
Headers
Header Components
There are three header styles: 1. normal; 2. normal plus a button; 3. normal plus a button and search box.
1. Normal
App Name Here
<header class="product-header">
<h2 class="product-header__name">
<a href="/"> App Name Here</a>
</h2>
</header>
2. With button
App Name Here
<header class="product-header">
<h2 class="product-header__name">
<a href="/">App Name Here</a>
</h2>
<a href="/">
<button class="btn btn--primary">Header Button</button>
</a>
</header>
3. With button and search
<header class="product-header">
<div class="product-header__links">
<h2 class="product-header__name">
<a href="/">App Name Here</a>
</h2>
<a href="/project">
<button class="btn btn--primary">Header Button</button>
</a>
</div>
<form class="search-form">
<input class="input" type="text" name="search" placeholder="Placeholder text">
<input class="btn btn--primary" type="submit" value="Search!">
</form>
</header>
Intros
Page/App Introduction
Use this component to introduce why your app exists and what functions it serves. This also serves well as a high-level page description if you app contains multiple pages.
The introduction component will normally be the inside the first section element in the body of your app.
<h6 class="label label--section">Intros</h6>
<h2>Page/App introduction</h2>
<p>Use this component to introduce why your app exists and what functions it serves.
This also serves well as a high-level page description if you app contains multiple pages.</p>
Tables
Table Components
Organize and display data with two distict table styles: plain and bordered.
1. Plain
Title | Year Published | Protagonist |
---|---|---|
Crime and Punishment | 1866 | Rodion Raskolnikov |
The Idiot | 1868–69 | Prince Myshkin |
The Brothers Karamazov | 1879–80 | Alyosha Karamazov |
<table class="table table--plain">
<thead>
<tr>
<th>Title</th>
<th>Year Published</th>
<th>Protagonist</th>
</tr>
</thead>
<tbody>
<tr>
<td>Crime and Punishment</td>
<td>1866</td>
<td>Rodion Raskolnikov</td>
</tr>
<tr>
...
</tr>
</tbody>
</table>
1a. Plain with row labels
Top three guitarists: |
Jimi Hendrix | Eric Clapton | Eddie Van Halen |
Largest countries: |
1. Russia | 2. Canada | 3. United States |
Most-spoken languages: |
1. Chinese | 2. Spanish | 3. English |
<table class="table table--plain">
<tbody>
<tr>
<td>
<h6 class="label label--primary">Top three guitarists:</h6>
</td>
<td>Jimi Hendrix</td>
<td>Eric Clapton</td>
<td>Eddie Van Halen</td>
</tr>
<tr>
...
</tr>
</tbody>
</table>
2. Bordered
Title | Year Published | Protagonist |
---|---|---|
Crime and Punishment | 1866 | Rodion Raskolnikov |
The Idiot | Prince Myshkin | 1868–69 |
The Brothers Karamazov | 1879–80 | Alyosha Karamazov |
<table class="table table--bordered">
<thead>
<tr>
<th>Title</th>
<th>Year Published</th>
<th>Protagonist</th>
</tr>
</thead>
<tbody>
<tr>
<td>Crime and Punishment</td>
<td>1866</td>
<td>Rodion Raskolnikov</td>
</tr>
<tr>
...
</tr>
</tbody>
</table>
Forms
Forms and Text Fields
These components allow users to input, edit, and select text.
The layout of a form is left to the desires of the developer. Below, the layout of item #1 has been customized, while the layout of item #2 is what the form component will look like off the shelf.
1. Inputs and labels, horizontal layout
<form class="form">
<div class="form__input-wrapper">
<span class="smalltext">First name*</span>
<input class="input" type="text" name="first_name" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Last name*</span>
<input class="input" type="text" name="last_name" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Email*</span>
<input class="input" type="text" name="email" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Website</span>
<input class="input" type="text" name="website" value="">
</div>
</form>
2. Inputs and labels, vertical layout
<form class="form form--vertical">
<div class="form__input-wrapper">
<span class="smalltext">First name*</span>
<input class="input" type="text" name="first_name" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Last name*</span>
<input class="input" type="text" name="last_name" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Email*</span>
<input class="input" type="text" name="email" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Website</span>
<input class="input" type="text" name="website" value="">
</div>
</form>
3. Inputs and labels with errors
<form class="form">
<div class="form__input-wrapper">
<span class="smalltext">First name*</span>
<input class="input input--error" type="text" name="first_name" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Last name*</span>
<input class="input input--error" type="text" name="last_name" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Email*</span>
<input class="input input--error" type="text" name="email" value="">
</div>
<div class="form__input-wrapper">
<span class="smalltext">Website</span>
<input class="input" type="text" name="website" value="">
</div>
</form>
4. Read-only input
<form class="form">
<div class="form__input-wrapper">
<span class="smalltext">First name*</span>
<input class="input" type="text" value="Bart" readonly tabindex="-1">
</div>
</form>
5. Checkboxes
<form class="form">
<div class="form__input-wrapper">
<input type="checkbox" name="types" id="photographer" value="photographer">
<label for="photographer" id="photog-label">Photographer</label>
</div>
<div class="form__input-wrapper">
...
</div>
</form>
6. Checkboxes with label
<h6 class="label label--secondary">Creative type:</h6>
<form class="form">
<div class="form__input-wrapper">
<input type="checkbox" name="types" id="photographer" value="photographer">
<label for="photographer" id="photog-label">Photographer</label>
</div>
<div class="form__input-wrapper">
...
</div>
</form>
7. Select box (dropdown)
<form class="form">
<div class="form__select-wrapper">
<select>
<option disabled selected>Select a section</option>
<option value="world">World</option>
<option value="us">U.S.</option>
</select>
</div>
</form>
8. Text area
<textarea class="input" name="email_text" rows="8" cols="150" placeholder="Placeholder text for the text area."></textarea>
Search
Search Box and Submit Button
For when you'll prompt a user to look up a record within your app.
Note: the second example contains optional features (radio buttons to change search type, help link to toggle instructions for advanced searches, typeahead styles). Use as needed.
1. Search and submit
<form class="search-form">
<input class="input" type="text" name="search" placeholder="Placeholder text">
<input class="btn btn--primary" type="submit" value="Search!">
</form>
2. Search and submit with types
Search by:
<div class="search">
<div class="search__btn-wrapper">
<h6 class="label label--secondary">Search by:</h6>
<div>
<input type="radio" id="location" name="search" checked>
<label for="location" class="search__filter-buttons">Location</label>
</div>
<div>
<input type="radio" id="name" name="search">
<label for="name" class="search__filter-buttons">Name</label>
</div>
</div>
<form class="search-form">
<input class="input" type="text" name="search" placeholder="Placeholder text">
<input class="btn btn--primary" type="submit" value="Search!">
<span class="search-form__help search__help-link">
<a class="link" href="#">Help</a>
</span>
</form>
<div class="instructions">
<div class="instructions__intro">Advanced search capabilities</div>
<div class="instructions__term">
<span class="instructions__term--small">By slug:</span> slug:stocks-tracker-2017
</div>
<div class="instructions__term">
...
</div>
<span class="instructions__close search__help-link">
<a class="link" href="#">Close</a>
</span>
</div>
</div>
Links
Links
There are two styles: active and normal.
1. Active
Active Link
<a class="link link--active" href="/">Active Link</a>
2. Normal
Normal Link
<a class="link" href="/">Active Link</a>
Typography
Typography Styles
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit nisi eligendi iure eveniet rerum autem soluta illo, rem, ullam iusto!
1. Big number
1,234
<span class="big-number">1,234</span>
2. Inline code
This is an inline code example.
<p>This is an <span class="inline-code">inline code</span> example.</p>
3. Label style #1
Primary Label Example
<h6 class="label label--primary">Primary Label Example</h6>
5. Label style #2
Secondary Label Example
<h6 class="label label--secondary">Secondary Label Example</h6>
4. Label style #3
Section Label Example
<h6 class="label label--section">Section Label Example</h6>
Toaster
Toaster, a.k.a. Snackbar
Brief feedback for an action through a message at the bottom of the screen. We recommend this library.
Examples: success | error | message
1. Success
<div class="toast" style="opacity: 1; bottom: 0px;">
<div class="body done">Updated!</div>
</div>
2. Error
<div class="toast" style="opacity: 1; bottom: 0px;">
<div class="body error">Something went wrong.</div>
</div>
3. Message
<div class="toast" style="opacity: 1; bottom: 0px;">
<div class="body message">Message displayed here.</div>
</div>
Cards
Cards
There are two different card styles: one with a header and one without.
1. Card, with header
Card Header
Put whatever you want in this space. Maybe a paragraph, like the one you're reading now.
<div class="card card--header">
<h3>Card Header</h3>
<div class="card--content">
<p>Put whatever you want in this space. Maybe a paragraph, like the one you're reading now.</p>
<button type="button" name="button" class="btn btn--primary">Or a button</button>
<p><a class="link" href="/1.0.0">Perhaps a link?</a></p>
</div>
</div>
2. Card, without header
Put whatever you want in this space. Maybe a paragraph, like the one you're reading now.
<div class="card card--plain">
<div class="card--content">
<p>Put whatever you want in this space. Maybe a paragraph, like the one you're reading now.</p>
<button type="button" name="button" class="btn btn--primary">Or a button</button>
<p><a class="link" href="/1.0.0">Perhaps a link?</a></p>
</div>
</div>
Pagination
Pagination
Breaking out large datasets into smaller, more manageable pages. If you're using React, we recommend this pagination library.
1. Pagination
<ul class="pagination">
<li><a href="/"><span>Prev</span></a></li>
<li><a href="/">1</a></li>
<li><a href="/">2</a></li>
<li><a href="/">3</a></li>
<li><a href="/" class="current">4</a></li>
<li><a href="/">5</a></li>
<li><a href="/"><span>Next</span></a></li>
</ul>
Formatting
Formatting
Reference these snippets to format dates and times.
1. Postgresql date formatting
to_char(timestamp, 'Mon DD, YYYY') outputs Apr 25, 2018.
to_char(timestamp, 'Dy, Mon DD, YYYY') outputs Wed, Apr 25, 2018.
to_char(timestamp, 'Dy, Mon DD, YYYY FMHH:MI am') outputs Wed, Apr 25, 2018 4:00 pm.
2. Moment.js date formatting
moment(timestamp).format('MMM DD, YYYY') outputs Apr 25, 2018.
moment(timestamp).format('ddd, MMM DD, YYYY') outputs Wed, Apr 25, 2018.
moment(timestamp).format('ddd, MMM DD, YYYY h:mm a') outputs Wed, Apr 25, 2018 4:00 pm.