For Developers‎ > ‎

Web Development Style Guide

Frontend features implemented using a combination of JavaScript, CSS and HTML in Chromium are known as WebUI features.  Developers coding for these features should adhere to the following rules just as C++ code must conform to the Chromium Coding Style.  For JavaScript, HTML and CSS, the Chromium style generally follows the Google JavaScript Style Guide and the Google HTML/CSS style guide.  Additional guidelines are listed below.

Separation of presentation and content

When designing a WebUI feature, split up the content you are presenting to the user (HTML) from the styling of the data (CSS).  Taking the concept a step further, the logic that controls the dynamic behavior of the content and presentation (JS) should also be separated.  This factoring helps by highlighting the meaning of the content and easing future changes to either the content, presentation or logic.

Another way to envision this principle is using the MVC pattern:

MVC Component Web Component
 Model  HTML
 View  CSS
 Controller  JS
 Separate content (HTML), presentation (CSS) and logic (JS) into separate implementation files.

Grit processing

We generally use grit to preprocess all resources (any .js, .html, or .css file is likely run through grit). This allows us to do:

<include src="assert.js"> assert(itsAllGood(), "It's not all good!");
which replaces the <include> tag with the contents of assert.js.

When doing this, don't close </include> tags as it's unnecessary and makes parsing these resources harder.



See the Google JavaScript Style Guide (but note that concerns for browser compatibility are not relevant for Chrome WebUI).
  • Use $('element-id') instead of document.getElementById.
  • Use single-quotes instead of double-quotes for all strings.
  • Omit curly braces for single-line if statements.
  • Use ES5 getters and setters
    • Use @type (instead of @return or @param) for JSDoc annotations on getters/setters
  • See Annotating JavaScript for the Closure Compiler for @-directives.
  • Prefer event.preventDefault() to return false; from event handlers


Use the closure compiler to identify some JS errors and enforce correct JSDoc annotations.
  • Add a compiled_resources2.gyp file to any new Web directory.
  • Ensure that the compiled_resources2.gyp file is included in third_party/closure_compiler/compiled_resources2.gyp (or somewhere in its include hierarchy).
  • Type Polymer elements by appending 'Element' to the element name, e.g. /** @type {IronIconElement} */
  • Use explicit nullability in JSDoc type information
      • Rather than @type {Object} use:
          • {!Object} for only Object
          • {!Object|undefined} for an Object that may be undefined
            • {?Object} for Object that may be null
          • Do the same for typedefs and Array (or any other nullable type)


        • Use on-tap for click events instead of on-click.
          • on-tap handlers should use stopPropagation() to prevent parents from handling the event where appropriate.
          • Note: calling stopPropagation() from an on-tap handler will not prevent on-click event handlers, so make sure that on-tap is used consistently throughout the page.
        See the Google HTML/CSS style guide (and again, browser compatibility issues are non relevant for Chrome WebUI).


        .raw-button:active {
         -webkit-box-shadow: none;
         background-color: rgb(253, 123, 42);
         background-repeat: no-repeat;
         border: none;
         min-width: 0;
         padding: 1px 6px;
        • Specify one selector per line.
          • Exception: One rule / one line frames in a @-webkit-keyframe (see below).
        • Opening brace on the same line as the last (or only) selector.
        • Two-space indentation for each declaration, one declaration per line, terminated by a semicolon.
        • Use shorthand notation when possible.
        • Alphabetize properties.
          • -webkit properties should be listed at the top, sorted alphabetically.
        • Insert a space after the colon separating property and value.
        • Do not create a class for only one element; use the element ID instead.
        • When specifying length values, do not specify units for a zero value, e.g., left: 0px; becomes left: 0;
        • Exception: 0% values in lists of percentages like hsl(5, 0%, 90%) or within @keyframe directives, e.g.:
          • @-webkit-keyframe animation-name { 0% { /* beginning of animation */ } 100% { /* end of animation */ } }
        • Use single quotes instead of double quotes for all strings.
        • Class names use dash-form.
        • If time lengths are less than 1 second, use millisecond granularity.
          • -webkit-transition: all 0.2s;
          • -webkit-transition: all 200ms;
        • Use two colons when addressing a pseudo-element (i.e. ::after, ::before, ::-webkit-scrollbar).
        • Use *-top/bottom instead of -webkit-*-before/after
          • *-top/bottom are easier to understand (before/after is confusingly similar to start/end)
          • -webkit-*-before/after have no advantage like -webkit-*-start/end do
        • Use scalable font-size units like % or em to respect users' default font size


        • When possible, use named colors such as red to enhance readability.
        • Prefer rgb() or rgba() with decimal values instead of hex notation (#rrggbb).
        • Hex is acceptable for shades of grey.
          • If the hex value is #rrggbb, use the shorthand notation #rgb.
        • Where equivalent, use the opacity property instead of rgba(0, 0, 0, a).


        • Don't embed data URIs in source files (anything that's not generated). Grit does this for you automatically at build time.
          • background-image: url(data:image/jpeg;base64,...);
          • background-image: url('file/in/the/source/tree.jpg');


        .suboption {
         -webkit-margin-start: 16px;

        #save-button {
         color: #fff;
         left: 10px;

        html[dir='rtl'] #save-button {
         right: 10px;
        • For the properties that WebKit currently supports, use the RTL-friendly properties:
          • x-left -> -webkit-x-start
          • x-right -> -webkit-x-end
          • Where x is either margin, padding or border
          • text-align: left -> text-align: start
          • text-align: right -> text-align: end
          • left/right: <length> when positioning will use the [dir] of the page, so if you set both left will apply when [dir='ltr'].
        • For properties that do not have RTL-friendly alternatives, use html[dir='rtl'] to specify the RTL version of said property.


        See the Google HTML/CSS style guide.


        <!doctype html>
        <html i18n-values="dir:textdirection">
         <meta charset="utf-8">
         <title i18n-content="myFeatureTitle"></title>
         <link rel="icon" href="feature.png">
         <link rel="stylesheet" href="feature.css">
         <script src="feature.js"></script>


        • Specify <!DOCTYPE HTML>.
        • Set the dir attribute of the html element to the localized ‘textdirection’ value.
        • Specify the charset, UTF-8.
        • Link in image, icon and stylesheet resources.
          • Do not add inline styling to elements.
        • Include the appropriate JS scripts.
          • Do not add JS to element event handlers.


        <h3 i18n-content="autofillAddresses"></h3>
        <div class="settings-list">
         <list id="address-list"></list>
           <button id="autofill-add-address" i18n-content="autofillAddAddress"></button>

        <if expr="pp_ifdef('chromeos')">
         <a href=""
             target="_blank" i18n-content="helpButton"></a>
        • Element IDs use dash-form or camelCase
          • camelCase may result in simpler access to Polymer local DOM (this.$.camelCase instead of this.$['dash-form'])
        • For i18n-content use javaScriptCase.
        • Adhere to the 80-column limit.
          • Indent 4 spaces when wrapping a previous line.
        • Add 2 space indentation in each new block.
        • Localize all strings using i18n-content attribute.
        • Use double-quotes instead of single-quotes for all attributes.
        • Do not close single tags.
          • <input type="radio" />
        • Use the button element instead of <input type="button">.
        • Do not use <br>; place blocking elements (<div>) as appropriate.
        • Do not use spacing-only divs; set the margins on the surrounding elements.
        • Only use <table> elements when displaying tabular data.
        • Do not use the for attribute of <label>.
          • If you're labelling a checkbox, put the <input> inside the <label>
          • If you're labelling purely for accessibility, e.g. a <select>, use aria-labelledby


        • For property change observers, prefer observers with no arguments (use within the observer instead).
          Reason: Brevity. Change observers actually take two arguments, newValue and oldValue, the order of which changed from .5 to 1.0. Unless oldValue is required (which is rare), it is simpler and slightly more clear to use in the observer.
        properties: {
          foo: {observer: 'fooChanged_'}
        fooChanged_: function() {
 = this.derive(;

        • Use a consistent ordering in the “prototype” object passed to Polymer():
          • is
          • behaviors
          • properties (public, then private_)
          • hostAttributes
          • listeners, observers
          • created, ready, attached, detached
          • public methods
          • event handlers, computed property functions and private methods
        • Use camelCase for element IDs to simplify local DOM accessors (i.e. this.$.camelCase instead of this.$[‘dash-case’]).