This guide will be deprecated soon!

CommCare HQ is currently undergoing a migration to Bootstrap 5. You can find the updated style guide here.

This section discusses the most basic elements of design on HQ. Much of this information is a level of detail that developers don't deal with on a day-to-day basis: the fonts, colors, etc. that underlie the classes and widgets used to build pages.

CommCare HQ Style Guide (Bootstrap 5)

Accessibility

Dimagi’s product design team firmly believes that web and software experiences should be accessible for everyone, regardless of abilities or impairments.

Overview

Accessible products give every user the same benefits regardless of ability and can adapt to any user in any context. Disabilities can be situational (an end user with typical vision may struggle to view their screen in a bright or sunny environment), temporary (a person with a broken wrist may not be able to type in HQ but will regain ability when healed), and long-lasting (barriers from birth, an illness, disease, accident, or developed over age; some may not consider themselves to have disabilities even if they experience functional limitations). We design and build products for everyone.

"Everyone" includes

  • 18% of adults with vision impairment (source)
  • 8.6% of adults with hearing trouble (16.8% of U.S. adults!) (source and source)
  • 15% of adults with physical functioning difficulty (source and source)
  • 4.4% of adults with cognitive disabilities (source)

Consider the following barriers when designing and coding

  • Blindness (may use screen reader, lack access to mouse, rely on text over visual information
  • Low-Vision (may use screen readers/magnifiers, high contrast or monochrome displays; maximize readability and visual clarity; try NoCoffee plugin
  • Color-blindness (may not be able to differentiate between some colors; test designs in a color-blind simulator)
  • Deaf and Hard-of-Hearing (may rely on captioning and alternative representations of audio
  • Physical Disabilities (may rely on keyboards, trackballs, voice recognition or assistive tech, may lack mouse access
  • Cognitive Disabilities (may have limited working memory, problem solving, attention, reading/linguistic/visual comprehension, sensitivity to flashing content; try to design linearly and focus on heuristics that have to do with cognitive load and memory)

Color-blindness: A11y Color Contrast Standards

A11y check
AA CONTRAST 4.86:1 AAA Contrast 7.01:1
AAA Contrast 12.05:1 AAA Contrast 11.07:1

Quick ways to test web accessibility

  • Keyboard Navigation: Test if modified code is navigable by keyboard, an effective way to ensure page navigability and screen reader visibility. More information and tips here.
  • Explore the Accessibility Tree: Use Chrome DevTools' accessibility feature to view the accessibility tree of a page under development, understanding how page elements are included, visible, and organized. This is especially helpful for understanding what a specific element is, how it’s labeled, and how it’s defined in relation to other elements on the screen.
  • Use a Screen Reader: Free options like VoiceOver for Mac, ORCA for Linux, and NVDA for Windows can assist in testing accessibility. Warning: different screen readers can read the same webpage differently so using one is a good launching point but it is also recommended to utilize different screen readers in final testing.
  • Check color contrast:We aim for AA compliant color contrast. You can check color contrast in tools such as https://webaim.org/resources/contrastchecker/.
  • WAVE Browser Extension: WAVE which identifies Web Content Accessibility Guideline (WCAG) errors

  • Keep in mind that this list is not exhaustive and covers only a portion of what makes a site accessible to all users. Ensuring accessibility is an ongoing commitment to creating inclusive digital experiences for everyone.

Focusability, Tabbability, and Visibility

tabindex Attribute

The tabindex attribute specifies the tab order of an element and determines whether an element can receive keyboard focus. Here are some scenarios where you might use tabindex:

  • Focusable but Not Natively Focusable Elements: Some elements like <div> or <span> are not natively focusable, but you might want them to receive focus for user interaction. In such cases, you can add tabindex="0" to make them focusable. Note: we avoid using custom focus order using tab index with values above 0. Instead, make sure DOM elements are ordered correctly for navigability, then modify visual positioning with CSS if needed.
  • Remove Focusability: to explicitly remove an item set tabindex="-1"
  • Dynamic Focus Control: If you have dynamically generated or hidden elements that need to become focusable under certain conditions, you can dynamically add or remove the tabindex attribute.
aria-hidden Attribute

The aria-hidden attribute indicates whether an element is visible or hidden to assistive technologies. It does not affect the visual rendering of the page. Here are some scenarios where you might use aria-hidden:

  • Hiding Decorative Elements: If you have decorative or presentational elements that should be hidden from screen readers, you can use aria-hidden="true".
  • Dynamic Content Updates: When dynamically updating content, you may want to temporarily hide or show certain elements from assistive technologies without altering their visual display.
  • Modal Dialogs or Popovers: When displaying modal dialogs or popovers, you may want to hide the underlying content from screen readers to prevent confusion.
When to Use Each

Use tabindex when you need to remove or add tab focusability to an element.

Use aria-hidden when you need to hide elements from assistive technologies while keeping them visible on the page or dynamically toggle their visibility.

Common Mistakes (and how to fix them)

  1. Using Non-Semantic HTML Elements for Interactive Components

    Error: Using <div> or <span> elements for interactive components like buttons or links instead of using native HTML elements.

    <!-- Incorrect: Using <div> for button -->
    <div onclick="handleClick()">Click me</div>
    <!-- Correct: Using <button> for button -->
    <button onclick="handleClick()">Click me</button>

    Fix: Replace non-semantic elements with appropriate semantic HTML elements like <button> for buttons and <a> for links. This fix also ensure that by creating interactive elements that cannot be accessed or operated using the keyboard.

  2. Missing or Incomplete ARIA (Accessible Rich Internet Applications) Attributes

    Error: Failing to provide necessary ARIA attributes or providing incomplete information, which can result in screen readers not conveying the correct information to users.

    <!-- Incorrect: Missing aria-label attribute for button with no text -->
    <button>×</button>
    <!-- Correct: Button with aria-label to convey visual information -->
    <button aria-label="Close">×</button>

    Fix: Include essential ARIA attributes like aria-label or aria-labelledby to provide meaningful information to assistive technologies when symbols or other visual information convey information that is otherwise not present.

  3. Inconsistent Use of ARIA Attributes

    Error: Inconsistently using ARIA attributes across similar UI components, leading to confusion for users relying on assistive technologies.

    <!-- Incorrect: Inconsistent use of aria-hidden -->
    <div id="modal1" aria-hidden="true">Modal 1 Content</div>
    <div id="modal2">Modal 2 Content</div>
    <!-- Correct: Consistent use of aria-hidden -->
    <div id="modal1" aria-hidden="true">Modal 1 Content</div>
    <div id="modal2" aria-hidden="true">Modal 2 Content</div>
  4. Overusing ARIA attributes

    Error: Using ARIA attributes unnecessarily can clutter the code and potentially confuse users or interfere with native accessibility features. This is often a crutch needed when not using semantic HTML (Semantic means "relating to meaning". Writing semantic HTML means using HTML elements to structure content based on each element's meaning, not its appearance.)

    <!-- Incorrect: Using a clickable div rather than button element -->
    <div role="button" tabindex="0" aria-label="Click me" aria-describedby="button-description">Click me</div>
    <!-- Correct: Minimal use of ARIA attributes -->
    <button>Click me</button>

    Fix: Use ARIA attributes only when necessary to supplement or enhance the accessibility of UI components, avoiding unnecessary or redundant attributes.

By avoiding these common coding errors and following best practices for ARIA implementation, you can ensure that your front-end code adheres to ARIA guidelines and provides a more accessible user experience for all users.

Typography

Font choice can have a strong yet subtle effect on how users perceive content. HQ uses Nunito Sans as its default font. This is embdedded in our base template and is consistent with dimagi.com.

Further reading: The science behind fonts (and how they make you feel)

Nunito Sans H1

Nunito Sans H2

Nunito Sans H3

Nunito Sans H4

Nunito Sans H5
Nunito Sans H6

Nunito Sans paragraph

Nunito Sans strong

Nunito Sans emphasis

Nunito Sans H1

Nunito Sans H2

Nunito Sans H3

Nunito Sans H4

Nunito Sans H5
Nunito Sans H6

Nunito Sans paragraph

Nunito Sans strong

Nunito Sans emphasis

Colors

Use color for communication over decoration. Use of color should be purposeful, accessible, and help focus attention to what matters most.

We strive to establish recognizable patterns to guide users through the UI. CommCare uses similar palettes on both the mobile and server side. When combining colors, use white, light or bright text on a dark background. Use dark, black, or medium text on a light background. Use white or light text on a medium background.

As described above, many people are affected by various types of color blindness. It is important to make sure that colors are never the source of critical information. Also, when colors are used to compare information (legend of a bar or line chart) it is important that the colors used can be differentiated by people with each type of color blindness.

Colors for messaging and attention

#E73C27
@cc-att-neg-mid
Error, Negative Attention
Use to highlight an error, something negative or a critical risk. Use as text, highlights, banners or destructive buttons. Often called "danger", as in .btn-danger.

View shades
#EEC200
@cc-light-warm-accent-mid
Attention
Use for warning-level information, less severe than an error but still in need of attention. Often called "warning", as in .alert-warning.

View shades
#4ABA32
@cc-att-pos-mid
Success
Use when an action has been completed successfully, primarily for messaging. Rarely used for interacactive elements like buttons. Used in classes such as .alert-success.

View shades

Colors for interaction

#5C6AC5
@call-to-action-mid
Call to Action
Use for buttons, checkmarks, radio buttons or actionable primary icons. Do not use for text links. Used for .btn-primary.

View shades
#004EBC
@cc-brand-mid
Link, Selection
Use for text links or to indicate that something is selected. Used in .active.

View shades
#00BDC5
@cc-light-cool-accent-mid
Accent Teal
Use for primary button on dark backgrounds. Use sparingly for secondary buttons, typically buttons indicating a download or upload. Corresponds with "info" classes like .btn-info.

View shades

Default and neutral colors

#1C2126
@cc-text
Ink Black
Default text color. Also used for footer.
#F2F2F1
@cc-bg
Background
Used for backgrounds that are light but distinct from the default white background, such as panel headers.
#685C53
@cc-neutral-mid
Neutral
Use for neutral visual indicators, typically borders or backgrounds.

View shades

Colors for signup

The user signup and login flows use a slightly different color palette than the rest of HQ so that they better match dimagi.com. Do not use these colors once the user is logged in.

#43467F
@color-purple-dark
Signup Purple
Use for banners or interactive elements in the signup and registration flow.
#E3D0FF
@color-purple-dark-inverse
Corresponds to signup purple.

Legacy colors

Minimize use of these colors.

#9060C8
@cc-dark-cool-accent-mid
Accent Purple
Avoid. Used occasionally for billing, web apps, and other unusual cases.

View shades
#FF8400
@cc-dark-warm-accent-mid
Accent Orange
Avoid. Used occasionally for billing, web apps, and other unusual cases.

View shades

Icons

Visual communication can be essential in scanning and understanding for populations whose first language may not be English. Please be sympathetic with the goal of cohesion and don’t use an icon for a purpose it was not intended for.

Consistent iconography in any user interface is critical to creating a product that is highly accessible across all different levels of literacy. Icons may need to be localized for different cultures and languages.

Good icons use simple, graphic shapes so they can be understood even at a small size. They have little detail. They are as universal as possible, consistent with other platforms.

Primary vs Secondary Icons

Primary icons are used for navigation or interaction. Primary icons are interactive, they change the surround environment or data. They likely don’t need to be coupled with text.

Secondary icons provide clarity. Secondary icons are used before text to communicate topical information.

Most of HQ's icons come from FontAwesome. All icons in FontAwesome are already built into HQ. Other icons have been custom created for HQ.

Common FontAwesome primary icons

<i class="fa-solid fa-plus"></i>
<i class="fa-solid fa-remove"></i>
<i class="fa-solid fa-search"></i>
<i class="fa-solid fa-angle-double-right"></i>
<i class="fa-solid fa-angle-double-down"></i>
<i class="fa-regular fa-trash-can"></i>

Common FontAwesome secondary icons

<i class="fa-solid fa-cloud-download"></i>
<i class="fa-solid fa-cloud-upload"></i>
<i class="fa-solid fa-warning"></i>
<i class="fa-solid fa-info-circle"></i>
<i class="fa-solid fa-question-circle"></i>
<i class="fa-solid fa-check"></i>
<i class="fa-solid fa-external-link"></i>

Custom HQ icons

<i class="fcc fcc-flower"></i>
<i class="fcc fcc-applications"></i>
<i class="fcc fcc-commtrack"></i>
<i class="fcc fcc-reports"></i>
<i class="fcc fcc-data"></i>
<i class="fcc fcc-users"></i>
<i class="fcc fcc-settings"></i>
<i class="fcc fcc-help"></i>
<i class="fcc fcc-exchange"></i>
<i class="fcc fcc-messaging"></i>
<i class="fcc fcc-chart-report"></i>
<i class="fcc fcc-form-report"></i>
<i class="fcc fcc-datatable-report"></i>
<i class="fcc fcc-piegraph-report"></i>
<i class="fcc fcc-survey"></i>
<i class="fcc fcc-casemgt"></i>
<i class="fcc fcc-blankapp"></i>
<i class="fcc fcc-globe"></i>
<i class="fcc fcc-app-createform"></i>
<i class="fcc fcc-app-updateform"></i>
<i class="fcc fcc-app-completeform"></i>
<i class="fcc fcc-app-biometrics"></i>

Custom HQ icons specific to form builder

<i class="fcc fcc-fd-text"></i>
<i class="fcc fcc-fd-numeric"></i>
<i class="fcc fcc-fd-data"></i>
<i class="fcc fcc-fd-variable"></i>
<i class="fcc fcc-fd-single-select"></i>
<i class="fcc fcc-fd-single-circle"></i>
<i class="fcc fcc-fd-multi-select"></i>
<i class="fcc fcc-fd-multi-box"></i>
<i class="fcc fcc-fd-decimal"></i>
<i class="fcc fcc-fd-long"></i>
<i class="fcc fcc-fd-datetime"></i>
<i class="fcc fcc-fd-audio-capture"></i>
<i class="fcc fcc-fd-android-intent"></i>
<i class="fcc fcc-fd-signature"></i>
<i class="fcc fcc-fd-multi-box"></i>
<i class="fcc fcc-fd-single-circle"></i>
<i class="fcc fcc-fd-hash"></i>
<i class="fcc fcc-fd-external-case"></i>
<i class="fcc fcc-fd-external-case-data"></i>
<i class="fcc fcc-fd-expand"></i>
<i class="fcc fcc-fd-collapse"></i>
<i class="fcc fcc-fd-case-property"></i>
<i class="fcc fcc-fd-edit-form"></i>

Creating New Icons

The process for creating a new icon has been updated and can be found in the Bootstrap 5 styleguide, as the process is the same for both Bootstrap 3 and Bootstrap 5.

Code Guidelines

At the atomic level, coding is CSS and LESS. Good styling code, like any good code, is reusable, DRY, and semantic.

Overview

Most of us don’t write much CSS. HQ uses Bootstrap 3, which gives us a consistent and fairly comprehensive set of styles. Most of the "styling" we do is picking the appropriate Bootstrap (or HQ) classes and then troubleshooting anything unexpected.

We use LESS to write styles. LESS is a fairly simple extension of CSS that allows for more maintainable and reusable styling by supporting variables, mixins, etc.

Reusable CSS is good for the same reasons reusable code is good everywhere else. On the front end, reusable code is also correlated with visual consistency and generally better UX. To that end, when creating a new page or section:

  • It should look very similar to related HQ pages.
  • It should look fairly similar to other HQ pages.
  • It should look somewhat like the rest of the internet.
Bootstrap takes care of a lot this: it gives us a consistent framework so our pages look like each other, and that framework is designed to resemble the rest of the internet.

Good styling is semantic, because that makes it easier for other developers to reuse. Ideally, a visual designer decides what an error looks like, or what a CRUD page looks like, and then developers only need to determine that they're displaying an error, or creating a CRUD page, and the look and feel is taken care of.

Classes like .bump-down { margin-top: 10px; } are problematic because it isn't clear when and why they should be used, so they get applied inconsistently and we end up with a site that looks a little bit...off...but it isn't obvious why. Bootstrap is a good example of a largely semantic system: classes have names like .btn-danger rather than .btn-red, to make it clear why you should use a particular class.

Style Hierarchy

Most styling should live in external LESS files.

Most HQ-specific styling lives in external LESS files, typically in corehq/apps/hqwebapp/static/hqwebapp/less.

App-specific styling can live in corehq/apps/style/static/APPNAME/less and then be included with <link> tags in the appropriate template.

Some pages use in-page <style> blocks. This isn't ideal for two reasons:

  • In-page styles can't be reused by other pages - but for the sake of a consistent experience, most styling shouldn't be specific to a single page.
  • In-page styles can't use LESS, so they tend to be less DRY and has to hard-code values like colors and dimensions, rather than using the standard values stored in LESS.
Inline styling is generally a bad idea for the same reasons as in-page styling: one-off styling isn't good for consistency and often isn't semantic.

Handling Z-Index

Disorganized z-indices lead to highly visible bugs.

Z-index gives you control over the stacking order of elements. The challenge is that it acts like a global variable and, like any global variable, gets hard to keep track of. HQ deals with this as best as it can, by declaring numeric z-index values as variables in variables.less and using the variables in other LESS files. This isn't perfect, but it at least gives us one place to define HQ-specific absolute z-index values - which also need to play nicely with Bootstrap's z-index list.

Most z-index issues arise from not having a good handle on all of the different values used in an application, but there are a few other complexities that occasionally cause problems:

  • Stacking levels: Z index isn't the only aspect of element stacking. Stacking is also affected by element positioning and floating. "Natural" stacking order, from top to bottom:
    • Positive z-index
    • z-index auto or 0
    • Inline elements
    • Floated elements
    • Block-level elements
    • Negative z-index
    • Background
  • Stacking context: Z-index isn't strictly global, it acts within a stacking context. There's a global context but may also be sub-contexts within that. The most common of these is that an element with a non-auto z-index creates a stacking context. This is intuitive: if you set a modal to z-index: 9999, you don’t have to set the z-index on all of its children to 1000, they just come along for the ride. But there are other properties that also create new stacking contexts where you might not expect it. position: fixed is one, translucent elements is another. The others are pretty obscure.