CALC Style Guide

Welcome to the CALC Style Guide! Here you’ll find the design building blocks of the site, from basics like typography and colors, to components such as form elements, to sample page layouts. This guide assumes knowledge of html, css, and other technologies used to build this website.

CALC's content is structured using 18F's standard voice, which is described in the 18F Content Guide.

CALC uses Bourbon and Neat as the foundation for its grid. Its visual styles are based on the U.S. Web Design System (USWDS), with alterations where deemed appropriate for branding and functionality.

While not all parts of the site adhere to a single unifying philosophy, we try to build new parts in accordance with Aaron Gustafson's three maxims for progressive enhancement with JavaScript:

  1. Make sure all content is accessible and all necessary tasks can be completed without JavaScript turned on.
  2. Use JavaScript to generate any additional markup it needs.
  3. Apply no style before its time.

Accessibility

We think CALC should be usable by anyone (and as a federal website, it’s also the law). Therefore, we stick to the requirements laid down in the 18F accessibility guide. Based upon the WCAG2.0 AA standard, the guide includes pointers for such things as minimum color contrast for text, keyboard access, form creation, and more. There’s also a handy checklist to help you ensure that any new content you create for CALC is fully accessible.

Typography

Most typography-related styling is defined in base/_typography.scss and base/_variables.scss.

Example

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

Paragraph body text go paragraph body text go. Paragraph body text go. Paragraph body text go paragraph body text go. Paragraph body text go. Paragraph body text go paragraph body text go. Paragraph body text go. Paragraph body text go paragraph body text go. Paragraph body text go.Paragraph body text go paragraph body text go. Paragraph body text go.

  • An unordered list
  • Organizing many things
  • Order from chaos
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<p>Paragraph body text go paragraph body text go. Paragraph body text go. Paragraph body text go paragraph body text go. Paragraph body text go. Paragraph body text go paragraph body text go. Paragraph body text go. Paragraph body text go paragraph body text go. Paragraph body text go.Paragraph body text go paragraph body text go. Paragraph body text go.</p>
<ul>
  <li>An unordered list</li>
  <li>Organizing many things</li>
  <li>Order from chaos</li>
</ul>

Colors

Our color palette is grounded in a subtly gradated bluish gray, with shades of bright green for accent.

In order to ensure that text on the site is accessible (as mandated by Section 508 of the Rehabilitation Act), all text must have a minimum contrast ratio of 4.5:1 with its background color.

Text in a color with this symbol is okay to pair with white.

Do not pair text in one of these colors with white.

$color-black

$color-base

#021014

OK with white

$color-white

#ffffff

$color-gray-darkest

#092d39

OK with white

$color-gray-darker

#2d4d59

OK with white

$color-gray-dark

#436a79

OK with white

$color-gray

#547d8c

OK with white

$color-gray-medium

#7da1b0

Insuff. contrast

$color-gray-light

#c5d6de

Insuff. contrast

$color-gray-lighter

#ebf1f5

Insuff. contrast

$color-gray-lightest

#f2f7fa

Insuff. contrast

$color-green-darkest

#61701c

OK with white

$color-green-dark

#a0ad64

Insuff. contrast

$color-green

#bbcb70

Insuff. contrast

$color-green-light

#ccdc86

Insuff. contrast

$color-green-lighter

#dae6a3

Insuff. contrast

$color-green-bright

#ccde61

Insuff. contrast

$color-blue-darkest

0a2d39

OK with white

$color-blue-darker

#0c4c6f

OK with white

$color-blue-dark

#136b94

OK with white

$color-blue

#0770b5

OK with white

$color-blue-lightest

#d4f6fe

Insuff. contrast

$color-red-darkest

#981b1e

OK with white

$color-red-dark

#bc1630

OK with white

$color-red-lightest

#ffe0e0

Insuff. contrast

$color-gold

#fdb81e

OK with white

$color-gold-darkest

#825c1e

OK with white

$color-gold-lightest

#fbeebe

Insuff. contrast

Color combinations used for typography

Over white background

$color-black over white is the default style for the website. Only on rare occasions should type be colored differently than this.

$color-black ($color-base)

$color-gray-dark

Background-color: $color-white

Special situations: over colored backgrounds

These more colorful combinations are used sparingly in the CALC design, such as in the header and footer. They are included here primarily for the sake of completeness.

$color-white

$color-gray-light

$color-green-bright

Background-color: $color-gray-darkest

$color-black

Background-color: $color-green-light

$color-black

$color-gray-darker

Background-color: $color-gray-lighter

Part of the base template. New pages should extend data_explorer/templates/base.html to include the header, which is visible for reference purposes only below.

The header is made up of a few separate file includes and blocks in data_explorer/templates/base.html.

The "official government website" banner file can be found at data_explorer/templates/_banner.html.

The slim header for sub-pages consists of the logo and user menu, and is at data_explorer/templates/_header.html.

The header_extension block is used to add extra things to the header, such as the content in the header on the data explorer.

The header_nav block is used to include the default navigation. Some pages don't need this.

Example

Part of the base template. New pages should extend data_explorer/templates/base.html to include the footer, which is visible for reference purposes only below.

Example

Card Layout

Defined in components/_page.scss. The card layout is used on every page, and there are some general rules, detailed below, for using the styles successfully.

Basic layout:

Example

<body>
  <main>
    <div class="container">
      <div class="card">
        <div class="content">
          <h2>Section of great importance!</h2>
          <p>Some compelling content goes here.</p>
        </div>
      </div>
      <div class="card">
        <div class="content">
          <p>Thrilling, isn't it?</p>
        </div>
      </div>
    </div>
  </main>
</body>

By default, the cards are too wide for text-only and most form-based sections, so you may need to use the content--skinny body class.

Example

<body class="content--skinny">
  <main>
    <div class="container">
      <div class="card">
        <div class="content">
          <h2>Section of great importance!</h2>
          <p>Some compelling content goes here.</p>
        </div>
      </div>
      <div class="card">
        <div class="content">
          <p>Thrilling, isn't it?</p>
        </div>
      </div>
    </div>
  </main>
</body>

Some pages display a bit of information below the last card. Use the card__footer class here. Note the markup needs to go inside the top-level container to work properly.

Example

<body>
  <main>
    <div class="container">
      <div class="card">
        <div class="content">
          <h2>Section of great importance!</h2>
          <p>Some compelling content goes here.</p>
        </div>
      </div>
      <div class="card">
        <div class="content">
          <p>Thrilling, isn't it?</p>
        </div>
      </div>
      <div class="card__footer">
        <button type="submit" class="usa-button usa-button-link" name="cancel" data-a11y-dialog-show="cancel-dialog" formnovalidate="">I've changed my mind; abort!</button>
      </div>
    </div>
  </main>
</body>

The data capture data_capture/templates/data_capture/step.html template is set up to expect step headings to occur in their own card; however, the designs for some steps call for a single-card look. To create this look, use the card--collapse-header class on main, which will remove the bottom border of the heading card and reduce the amount of padding applied to the second card.

Example

<body>
  <main class="card--collapse-header">
    <div class="container">
      <div class="card">
        <div class="content">
          <h2>Section of great importance!</h2>
          <p>Some compelling content goes here.</p>
        </div>
      </div>
      <div class="card">
        <div class="content">
          <p>Thrilling, isn't it?</p>
        </div>
      </div>
    </div>
  </main>
</body>

Ajax Form + Upload Widget

Our upload widget is implemented using the techniques outlined in Styling & Customizing File Inputs the Smart Way and Drag and Drop File Uploading by Osvaldas Valutis.

We use an <upload-widget> with a nested <input is="upload-input"> to progressively enhance the front end. However, using them is rarely needed in practice, as frontend.upload.UploadWidget contains the Django widget for rendering all the required HTML.

Form Submission

Due to the technical limitations of HTML5, forms containing the progressively-enhanced upload widget must be submitted via ajax. This can be accomplished via a custom <form is="ajax-form"> web component.

frontend.ajaxform contains utilities for processing forms submitted by this web component in a progressively-enhanced way.

For a simple ajax form code example that also embeds an upload widget, see styleguide/ajaxform_example.py and styleguide/templates/styleguide_ajaxform_example.html.

Example

Some checkboxes
Some radios
CSV only, please.

Accessibility

Any response from the ajax form that dynamically updates content on the page instead of redirecting the user to a new page should contain an <alerts-widget> which wraps a message to inform users about what just happened. This will automatically be focused when the content is injected into the page, allowing screen readers to announce it.

To experience this in action, try submitting invalid data into the example form above.

Graceful Degradation

Note that the upload widget gracefully degrades to a standard HTML file input if either JS is disabled or any required HTML5 features are unavailable:

Example (no JavaScript)

XLS, XLSX, or CSV format, please.

Existing Filenames

In some cases, it may be preferable to indicate to a user that a file upload field is not only optional, but that a default which the user has uploaded earlier will be used if nothing else is provided.

Examples

The baseline experience simply explains to the user that leaving the field blank will result in the use of their previously-uploaded file.

Example (no JavaScript)

You've already uploaded boop.csv. You can keep using it or select a new file to replace it.
XLS, XLSX, or CSV format, please.

The server, of course, will not receive any data if the user doesn't supply a file. Finding and using the previously uploaded file is the server's responsibility.

However, if proper browser support exists, the user experience is progressively enhanced: the widget will appear populated, but as with the baseline experience, the server will not actually receive any data unless the user explicitly chooses a different file.

Example

You've already uploaded boop.csv. You can keep using it or select a new file to replace it.
XLS, XLSX, or CSV format, please.

Buttons

Use primary buttons to indicate primary actions, default to indicate less important actions, and secondary to indicate actions such as cancelling a process or deleting information.

Styling is defined in components/_buttons.scss.

Example

<button>Default button</button>
<button class="usa-button usa-button-primary">Button</button>
<input class="usa-button usa-button-primary" type="button" value="Input">
<input class="usa-button usa-button-primary" type="submit" value="Submit">
<button class="usa-button usa-button-disabled">Disabled</button>
<button class="usa-button usa-button-secondary">Secondary</button>
<button class="button-green">Green</button>
<button class="usa-button usa-button-link">Link button</button>

Steps Widget

The steps widget can be used to visualize the user's progress through a multi-step process.

Users assisted by screen readers will hear an audio description of the visualization, e.g. "Step 2 of 3", followed by the name of the current step.

Rather than writing out the raw HTML of the steps widget, we recommend using frontend.steps.StepsWidget.

Example

The markup used by this widget is defined in frontend/steps.html, while styling is in components/_steps.scss.

Alerts

These are similar to the US Web Design Standards, but add a stroke and the CALC standard border radius.

Styling is defined in components/_alerts.scss.

Example

<div class="usa-alert usa-alert-error" role="alert">
  <h4>Error!</h4>
  <p>Better get out your eraser.</p>
</div>

Example

<div class="usa-alert usa-alert-success" role="alert">
  <h4>Success alert</h4>
  <p>Hooray!</p>
</div>

Example

<div class="usa-alert usa-alert-warning" role="alert">
  <h4>Warning alert</h4>
  <p>Danger, danger, Will Robinson!</p>
</div>

Example

<div class="usa-alert usa-alert-info" role="alert">
  <h4>Info alert</h4>
  <p>Now you have The Information!</p>
</div>

Tables

Defined in components/_tables.scss.

When displaying data in tables, be sure to add the number class to cells that contain numbers. This will monospace and right-align those columns. For dollar amounts, you'll need to also add the number--currency class to get the dollar sign to appear. You can add a highlight-on-hover effect to a table's rows by including the hoverable class on the table.

Example

SIN Service proposed Minimum education Minimum years of experience Price offered to GSA (including IFF)
132-51 Project Manager Bachelors 5 115.99
132-17 Software Programmer, Associate Bachelors 0 37.59
132-17 Software Programmer I Bachelors 3 41.59
132-17 Software Programmer II Bachelors 5 52.03
132-17 Software Programmer III Bachelors 7 65.72
<table class="hoverable">
  <thead>
    <tr>
      <th>SIN</th>
      <th>Service proposed</th>
      <th>Minimum education</th>
      <th class="number">Minimum years of experience</th>
      <th class="number">Price offered to GSA (including IFF)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>132-51</td>
      <td>Project Manager</td>
      <td>Bachelors</td>
      <td class="number">5</td>
      <td class="number number--currency">115.99</td>
    </tr>
    <tr>
      <td>132-17</td>
      <td>Software Programmer, Associate</td>
      <td>Bachelors</td>
      <td class="number">0</td>
      <td class="number currency">37.59</td>
    </tr>
    <tr>
      <td>132-17</td>
      <td>Software Programmer I</td>
      <td>Bachelors</td>
      <td class="number">3</td>
      <td class="number currency">41.59</td>
    </tr>
    <tr>
      <td>132-17</td>
      <td>Software Programmer II</td>
      <td>Bachelors</td>
      <td class="number">5</td>
      <td class="number currency">52.03</td>
    </tr>
    <tr>
      <td>132-17</td>
      <td>Software Programmer III</td>
      <td>Bachelors</td>
      <td class="number">7</td>
      <td class="number currency">65.72</td>
    </tr>
  </tbody>
</table>

When errors are displayed in tables, they look like this. Note that this markup is automatically generated on Step 3.

Example

Review submitted price list data
SIN(s) proposed Service proposed (e.g. job title/task) Min. education (or certification level) Min. years of experience Unit of issue Price offered to GSA (including IFF)
none Button Presser NA 1 Hour $9.00
none Button Presser NA all of them Hour $9.00

Excel Tables

Defined in components/_exceltables.scss.

Sometimes we need to display "screenshots" of Microsoft Excel tables to users, to communicate what kind of spreadsheet they need to upload. Doing this with standard HTML tables that are styled to look like excel tables allows us to accomplish this in an accessible and easily changeable way.

The base class just styles the table to look like a standard Excel sheet without any styling:

Example

A1B1
A2B2
<div class="excel-wrapper">
  <table class="excel">
    <tr><td>A1</td><td>B1</td></tr>
    <tr><td>A2</td><td>B2</td></tr>
  </table>
</div>

But we have extra classes that we can layer on top to emulate the styling of specific contract vehicle spreadsheets.

For example, here's a style for Schedule 70 proposed price lists:

Example

SIN(s) PROPOSED SERVICE PROPOSED (e.g. Job Title/Task) MINIMUM EDUCATION/CERTIFICATION LEVEL MINIMUM YEARS OF EXPERIENCE COMMERCIAL LIST PRICE (CPL) OR MARKET PRICES UNIT OF ISSUE (e.g. Hour, Task, Sq ft) MOST FAVORED CUSTOMER (MFC)
132-51 Project Manager Bachelors 5 $125 Hour All Commercial
<div class="excel-wrapper">
  <table class="excel excel-schedule-70">
    <tr>
      <td>SIN(s) PROPOSED</td>
      <td>SERVICE PROPOSED (e.g. Job Title/Task)</td>
      <td>MINIMUM EDUCATION/CERTIFICATION LEVEL</td>
      <td>MINIMUM YEARS OF EXPERIENCE</td>
      <td>COMMERCIAL LIST PRICE (CPL) OR MARKET PRICES</td>
      <td>UNIT OF ISSUE (e.g. Hour, Task, Sq ft)</td>
      <td>MOST FAVORED CUSTOMER (MFC)</td>
    </tr>
    <tr>
      <td>132-51</td>
      <td>Project Manager</td>
      <td>Bachelors</td>
      <td>5</td>
      <td>$125</td>
      <td>Hour</td>
      <td>All Commercial</td>
    </tr>
  </table>
</div>

Forms

Defined in components/_forms.scss.

Example

Helpful error message
<label for="input-type-text">Text input label</label>
<input id="input-type-text" name="input-type-text" type="text">

<label for="input-focus">Text input focused</label>
<input class="input-focus" id="input-focus" name="input-focus" type="text">

<fieldset class="fieldset-error">
  <span class="input-error-message" id="input-error-message" role="alert">Helpful error message</span>
  <label class="input-error-label" for="input-error">Text input error</label>
  <input id="input-error" name="input-error" type="text" aria-describedby="input-error-message">
</fieldset>

<label for="input-type-textarea">Text area label</label>
<textarea id="input-type-textarea" name="input-type-textarea"></textarea>

Example

<label for="options">Dropdown label</label>
<select name="options" id="options">
  <option value="value1">Option A</option>
  <option value="value2">Option B</option>
  <option value="value3">Option C</option>
</select>

Radio Buttons and Checkboxes

Because USWDS uses a slightly different HTML structure for radio buttons and checkboxes from Django, we need to use custom widgets from django-uswds-forms.

For a simple code example, see styleguide/radio_checkbox_example.py and styleguide/templates/styleguide_radio_checkbox_example.html.

Example

Radios
Checkboxes

Dates

We use a custom Django form field and widget from django-uswds-forms that offers three separate text fields for users to enter dates, as per the USWDS section on date input.

Additionally, we use a <uswds-date> to provide some optional dynamic functionality, such as automatically advancing focus to the next input field in the date whenever /, ., or - is pressed.

For a simple code example, see styleguide/date_example.py and styleguide/templates/styleguide_date_example.html.

Example

Date For example: 04 28 2016

Form Button Row

Defined in components/_formbuttonrow.scss.

The form-button-row widget is used to add common buttons to the bottom of forms in a multi-step process, such as the Data Capture Upload flow.

Example

Previous
Provide details about the contract.
<div class="form-button-row clearfix">
  <a href="#" class="usa-button usa-button-secondary button-previous">Previous</a>


  <div class="submit-group">
    <button type="submit" class="usa-button usa-button-primary">Next</button>
    <span class="submit-label">
      Provide details about the contract.
    </span>
  </div>

</div>

Expandable Area

The <expandable-area> web component makes it possible to progressively enhance an area to be initially collapsed, and expandable via user interaction. The first child element is assumed to be the expander (which is dynamically given the button role) while all of its siblings are the expandable content.

Example

Why are computers so hard to use?

Here is a paragraph of explanatory text.

Here is another paragraph of explanatory text.

<expandable-area>
  <p><strong>Why are computers so hard to use?</strong></h6>
  <p>Here is a paragraph of explanatory text.</p>
  <p>Here is another paragraph of explanatory text.</p>
</expandable-area>

When JavaScript isn't available, the hidden content is always shown:

Example (no JavaScript)

Why are computers so hard to use?

Here is a paragraph of explanatory text.

Here is another paragraph of explanatory text.

Styling for this component can be found in components/_expandablearea.scss.

Defined in components/_dialogs.scss and data-capture/modal-dialogs.js.

Modal dialogs provide a way of display a dialog, such as a confirmation message, and associated actions in a visually-pleasing, styleable manner. We use the a11y-dialog library for modal dialog support.

Due to the way a11y-dialog works, markup for the modals needs to be placed outside of the page's <main> element in order to be read properly by screenreaders. In templates, place modal markup in the {% block modals %} block.

Example

<button data-a11y-dialog-show="example-dialog">Open Dialog</button>

<!-- Note that any modal markup should be placed in {% block modals %}
otherwise screenreading will not work properly.
Screenreading will not work properly in this example for instance. -->
<div id="example-dialog" aria-hidden="true" class="dialog">
  <div class="dialog-overlay" tabindex="-1" data-a11y-dialog-hide></div>
  <div class="dialog-content" role="dialog" aria-labelledby="example-dialog-title" aria-describedby="example-dialog-description">
    <div role="document">
      <h1 id="example-dialog-title">
        This is an example dialog title
      </h1>

      <p id="example-dialog-description">
        Here is some content in the dialog.
        Click "Dismiss Dialog" or anywhere outside of this dialog to close me.
      </p>

      <div class="dialog-buttons">
        <button class="usa-button usa-button-primary" data-a11y-dialog-hide>
          Dismiss dialog
        </button>
      </div>
    </div>
  </div>
</div>

When JavaScript is not available, the activator element will do whatever it previously did before being modified to open a dialog.

Emails

Emails are delivered in both plain text and HTML formats. Our HTML emails are based on Lee Munroe's Really Simple Responsive HTML Email Template.

The base template used to render emails is at email/base.html, while common template tags are in the email_utils template tag library.

Examples of each email type that can be sent from CALC are listed below.

Compatibility Mode

Because we're designing the new parts of CALC to be progressively enhanced, they can actually work without JavaScript. One advantage of this approach is that in the rare case that the site doesn't work, a user can disable JavaScript in their browser and reload the page—it can potentially fix things.

However, there's a few problems with this:

  1. Most users don't know what JavaScript is, much less how to disable it.
  2. Even if a user knows what JavaScript is and how to disable it in their browser, they have no idea when a JavaScript error has actually occurred.

Fortunately, it is possible to use JavaScript to detect when a JavaScript error has occurred, so we do this on progressively enhanced CALC pages. Whenever a JS error occurs, a warning appears that allows users to opt-in to compatibility mode. If the user opts-in, the server will stop sending JS to the client, ensuring a baseline experience.

To see what this looks like in action, you can forcibly trigger a JS error on this page via the button below.

Updating the style guide

For details on how to update this style guide, see the Style Guide Documentation.