web.dev components
The web.dev platform includes various components to make it easy for content contributors to include common content features, like videos, side-by-side comparisons, and asides.
This post shows sample markup for each of web.dev's content components and provides guidance about how to use them effectively.
Component types #
- Asides
- Banners
- Block quotes
- Browser Compatibility
- Buttons
- Callouts
- Checkbox
- Code pattern
- Codepen
- Columns
- Code
- Compare
- Details
- Glitches
- Images
- Instructions
- Labels
- Lists
- Stats
- Tables
- Tabs
- Tooltips
- Video
Asides #
Use asides to provide information that's related to but distinct from the content in the body of the post or codelab. Asides should generally be short—no more than 2–3 lines.
Asides can contain links and formatted text, including code.
There are several kinds of asides, each for a different purpose.
Note asides #
{% Aside %}
Use the note aside to provide supplemental information.
{% endAside %}
Caution asides #
{% Aside 'caution' %}
Use the caution aside to indicate a potential pitfall or complication.
{% endAside %}
Warning asides #
{% Aside 'warning' %}
The warning aside is stronger than a caution aside; use it to tell the reader
not to do something.
{% endAside %}
Success asides #
{% Aside 'success' %}
Use the success aside to describe a successful action or an error-free status.
{% endAside %}
Celebration asides #
{% Aside 'celebration' %}
Use the celebration aside to celebrate events like a cross-browser launch.
{% endAside %}
Objective asides #
{% Aside 'objective' %}
Use the objective aside to define the goal of a process described in the body
copy.
{% endAside %}
Important asides #
{% Aside 'important' %}
Use the important aside to indicate a common problem that the reader wouldn't know
without specialized knowledge of the topic.
{% endAside %}
Key-term asides #
{% Aside 'key-term' %}
Use the key-term aside to define a term that's essential to understanding an
idea in the body copy. Key-term asides should be a single sentence that
includes the term in italics. For example, "A _portal_ is…"
{% endAside %}
Codelab asides #
{% Aside 'codelab' %}
Use the codelab aside to link to an associated codelab.
{% endAside %}
Update asides #
{% Aside 'update' %}
Use the update aside in select cases where updates concerning a developing
situation around a certain API or metric can be effectively communicated.
{% endAside %}
Banners #
Default banners #
Default banners can be added to site templates (for example, landing pages) to provide timely information to users (for example, an alert about an upcoming conference). Don't use default banners in the body of a post; instead, use the Aside component.
{% Banner %}This is an info banner. It supports Markdown.{% endBanner %}
{% Banner 'caution' %}This is a caution banner. It supports Markdown.{% endBanner %}
{% Banner 'warning' %}This is a warning banner. It supports Markdown.{% endBanner %}
{% Banner %}This is a neutral banner, used to display a discreet suggestion for the user. It supports Markdown.{% endBanner %}
Block quotes #
To include quotation in the body of an article, use <blockquote>
tag. You can include a <cite>
element indicating the quote's source at the end of a block quote:
<blockquote>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Proin dictum a massa sit amet ullamcorper.
</p>
<cite>
Jon Doe
</cite>
</blockquote>
You can also use a shortcode:
{% Blockquote 'Jon Doe' %}
[Lorem ipsum](#) dolor sit amet, consectetur adipiscing elit. Proin dictum
a massa sit amet ullamcorper.
{% endBlockquote %}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper.
Jon Doe
To embed a pull quote in an article, to emphasize a piece of text or a quote, you can use pullquote
class:
<blockquote data-type="pullquote">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Proin dictum a massa sit amet ullamcorper.
</p>
<cite>
Jon Doe
</cite>
</blockquote>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper.
Jon Doe
You can also use a shortcode with a pullquote
attribute:
{% Blockquote 'Jon Doe', 'pullquote' %}
[Lorem ipsum](#) dolor sit amet, consectetur adipiscing elit. Proin dictum
a massa sit amet ullamcorper.
{% endBlockquote %}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper.
Jon Doe
Browser compatibility table #
With the BrowserCompat
shortcode, you can embed an MDN - Browser Compatibility Data widget in your post. You have to pass in the dot-separated feature ID, as used on BCD Schema, e.g. for Web/API/BackgroundFetchEvent the ID is api.BackgroundFetchEvent
.
{% BrowserCompat 'api.BackgroundFetchEvent' %}
- Chrome 74, Supported 74
- Firefox, Not supported
- Edge 79, Supported 79
- Safari, Not supported
The widget will use 🗑 symbols to represent features that are deprecated:
- Chrome 1, Supported 1
- Firefox 1, Supported 1
- Edge 12, Supported 12
- Safari 1.3, Supported 1.3
The following JavaScript snippet, run from the DevTools console, will display the correct ID for a given MDN page that's currently open:
window.alert(document.querySelector(".bc-github-link")?.href.match(/title=(.+?)\+/)[1] ?? "No browser compat widget found on the page.")
Buttons #
In general, you shouldn't need to add buttons to your posts. These buttons are shown for reference.
Text buttons #
Icon buttons #
A default icon button:
An icon button with tooltip:
Callouts #
Codelab callouts #
In general, you shouldn't need to manually add a codelab callout to your page; instead, use the codelabs
field in the post's YAML, which will automatically append a codelab callout to the end of the post.
Self-assessment callouts #
See the Self-assessments post.
Checkbox #
To align a label to the checkbox wrap the label and checkbox in an element with a cluster gutter-base flex-align-start
class.
<div class="cluster gutter-base flex-align-start">
<input id="myCheckbox" type="checkbox" />
<label for="myCheckbox">Lorem ipsum dolor sit amet</label>
</div>
Code pattern #
A component that displays a demo and code snippets side by side, organized in tabs.
Component height is determined by the code snippet with the most code lines.
To change the component height, specify the height value in pixels in the shortcode.
{% CodePattern 'pattern-id', optional-height-in-px %}
<div>
HTML for the example-pattern
</div>
console.log('Javascript for the example-pattern');
document.body.append('Javascript for the example-pattern');
body {
background-color: red;
}
You can embed one of the existing patterns (from /content/en/patterns/
directory) or add a new one. Check out the examples and documentation on how to write new code patterns.
Codepen #
If you don't want to use your personal account, you can use the web-dev-codepen-external account to create a Codepen. Speak to a member of the tech writing team to get access to the login and password.
{% Codepen {
user: 'robdodson',
id: 'GRroyyX',
height: 300,
theme: 'dark',
tab: 'css,result',
allow: ['geolocation']
} %}
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare global {
export interface CodepenParam {
height?: number;
tab?: string;
theme?: string;
title?: string,
user: string,
width?: string | number;
id: string,
allow?: Array.<string>,
}
}
// empty export to keep file a module
export {};
Columns #
Any elements can be placed in a two-column layout by wrapping them in a <div class="switcher">
element. At smaller viewport sizes, elements in a two-column layout will shift to a stacked arrangement.
<div class="switcher">
<figure>
<img src="./image-small.png" alt="">
<figcaption>
Small image.
</figcaption>
</figure>
<figure>
<img src="./image-small.png" alt="">
<figcaption>
Small image.
</figcaption>
</figure>
</div>


Code #
See the Code post.
Compare #
{% Compare 'worse' %}
```text
Bad code example
```
{% endCompare %}
{% Compare 'better' %}
```text
Good code example
```
{% endCompare %}
Don't
Bad code example
Do
Good code example
Compare with caption #
{% Compare 'worse' %}
```text
Bad code example
```
{% CompareCaption %}
Explanation of why `example` is bad.
{% endCompareCaption %}
{% endCompare %}
{% Compare 'better' %}
```text
Good code example
```
{% CompareCaption %}
Explanation of why `example` is good.
{% endCompareCaption %}
{% endCompare %}
Don't
Bad code example
Explanation of why example
is bad.
Do
Good code example
Explanation of why example
is good.
Compare with custom labels #
{% Compare 'worse', 'Unhelpful' %}
Lorem ipsum [dolor sit amet](#), consectetur adipiscing elit. Proin dictum a
massa sit amet ullamcorper. `Suspendisse` auctor ultrices ante, nec tempus
nibh varius at.
{% endCompare %}
{% Compare 'better', 'Helpful' %}
Lorem ipsum [dolor sit amet](#), consectetur adipiscing elit. Proin dictum a
massa sit amet ullamcorper. `Suspendisse` auctor ultrices ante, nec tempus
nibh varius at.
{% endCompare %}
Unhelpful
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper. Suspendisse
auctor ultrices ante, nec tempus nibh varius at.
Helpful
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper. Suspendisse
auctor ultrices ante, nec tempus nibh varius at.
Compare in columns #
<div class="switcher">
{% Compare 'worse' %}
```text
Bad code example
```
{% CompareCaption %}
Explanation of why `example` is bad.
{% endCompareCaption %}
{% endCompare %}
{% Compare 'better' %}
```text
Good code example
```
{% CompareCaption %}
Explanation of why `example` is good.
{% endCompareCaption %}
{% endCompare %}
</div>
Don't
Bad code example
Explanation of why example
is bad.
Do
Good code example
Explanation of why example
is good.
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Enim necessitatibus incidunt harum reprehenderit laboriosam labore consequuntur quod. Doloribus, deleniti! Atque aliquam facilis labore odio similique provident illo culpa assumenda perspiciatis.
Details #
Basic details component #
{% Details %}
{% DetailsSummary %}
Details _summary_
{% endDetailsSummary %}
Lorem ipsum [dolor sit amet](#), consectetur adipiscing elit. Proin dictum a massa
sit amet ullamcorper. `Suspendisse` auctor ultrices ante, nec tempus nibh varius
at.
{% endDetails %}
Details summary
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper. Suspendisse
auctor ultrices ante, nec tempus nibh varius at.
Details component with preview #
{% Details %}
{% DetailsSummary %}
Details _summary_
This is an optional preview. Make your preview text match the first paragraph
of your panel text.
{% endDetailsSummary %}
Lorem ipsum [dolor sit amet](#), consectetur adipiscing elit. Proin dictum a massa
sit amet ullamcorper. `Suspendisse` auctor ultrices ante, nec tempus nibh varius
at.
{% endDetails %}
Details summary This is an optional preview. Make your preview text match the first paragraph of your panel text.
This is an optional preview. Make your preview text match the first paragraph of your panel text.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper. Suspendisse
auctor ultrices ante, nec tempus nibh varius at.
Details component with custom heading level #
The default heading level is h2
. To ensure the Details
component is in the correct place in the page hierarchy, add a custom heading argument to the DetailsSummary
shortcode. For example, if the component is in an h2
section, use an h3
heading.
{% Details %}
{% DetailsSummary 'h3' %}
Details _summary_
{% endDetailsSummary %}
Lorem ipsum [dolor sit amet](#), consectetur adipiscing elit. Proin dictum a massa
sit amet ullamcorper. `Suspendisse` auctor ultrices ante, nec tempus nibh varius
at.
{% endDetails %}
Details summary
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper. Suspendisse
auctor ultrices ante, nec tempus nibh varius at.
Details component in open state #
The Details
component is closed by default. If for some reason you want it open, add the open
argument to the Details
shortcode.
{% Details 'open' %}
{% DetailsSummary %}
Details _summary_
{% endDetailsSummary %}
Lorem ipsum [dolor sit amet](#), consectetur adipiscing elit. Proin dictum a massa
sit amet ullamcorper. `Suspendisse` auctor ultrices ante, nec tempus nibh varius
at.
{% endDetails %}
Details summary
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum a massa sit amet ullamcorper. Suspendisse
auctor ultrices ante, nec tempus nibh varius at.
Glitches #
Create a Glitch #
- Remix the web-dev-hello-webpage or web-dev-hello-express template.
- Click Project options and update the description of the Glitch.
- Update
README.md
. - Update
package.json
(if it exists). - Add the project to the web.dev team on Glitch.
- Set the avatar of the project to the web.dev logo.
Embed a Glitch #
{% Glitch {
id: 'tabindex-zero',
path: 'index.html',
previewSize: 0,
allow: []
} %}
<!-- Or just the Glitch ID -->
{% Glitch 'tabindex-zero' %}
It's OK to adjust the height
of the Glitch wrapper element if you need more or less space.
Shortcode object fields allow for modifying how the embed is presented:
- {
string | string[]
}allow?
List of feature policies of an IFrame either as an array of strings, or as a;
separated list. By default the following policies are enabled:'camera', 'clipboard-read', 'clipboard-write', 'encrypted-media', 'geolocation', 'microphone', 'midi'
- {
string
}id
ID of Glitch project. - {
string
}path?
Lets you specify which source code file to show. - {
number
}previewSize?
Defines what percentage of the embed should be dedicated to the preview, default is 100. - {
number
}height?
Height, in pixels, of the Glitch wrapper element.
Images #
See the Images and video post.
Instructions #
The Instruction component provides commonly used instructions for Glitch and Chrome DevTools. Use the Instruction component whenever possible to help ensure content consistency and make cross-site maintenance easier.
By default, each instruction is placed in an unordered list item. To use an ordered list, add an ol
argument to the shortcode. To use a paragraph, add a none
argument. See the Lists section of the Grammar, mechanics, and usage post for information about when to use each list type.
Instructions can be strung together to create multi-step processes.
Glitch instructions #
The most common Glitch instructions explain how to preview a Glitch sample app by using the remix
and preview
arguments in two consecutive Instruction
shortcodes:
{% Instruction 'remix' %}
{% Instruction 'preview' %}
- Click Remix to Edit to make the project editable.
- To preview the site, press View App. Then press Fullscreen
.
To explain how to open the Glitch console, use the console
argument:
- Click Terminal (note: if the Terminal button does not show you may need to use the Fullscreen option).
To explain how to create a new file in a Glitch, use the create
argument:
- Click New File and give it a name.
- Click Add This File.
To explain how to view a Glitch's source code, use the source
argument:
- To view the source, press View Source.
Reloading the page #
There are three ways to instruct users to reload the page.
If users are reloading an app, use the reload-app
argument:
- Reload the app.
If users are reloading a traditional web page, use the reload-page
argument:
- Reload the page.
If users are reloading a page for the purpose of profiling, use the start-profiling
argument:
- Click Start profiling and reload page
.
DevTools instructions #
Instruct users how to access any tab in DevTools by using the devtools-tabName
argument in the Instruction shortcode. For example, here are the instructions for the Performance tab:
- Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
- Click the Performance tab.
If you just need users to open DevTools, use the devtools
argument:
- Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
To tell users how to open the DevTools Command menu, use the devtools-command
argument:
- Press
Control+Shift+P
(orCommand+Shift+P
on Mac) to open the Command menu.
To tell users how to disable the cache, use this sequence:
{% Instruction 'devtools-network', 'ol' %}
{% Instruction 'disable-cache', 'ol' %}
- Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
- Click the Network tab.
- Select the Disable cache checkbox.
Instruct users how to run an audit in Lighthouse by using the audit-auditName
argument in the Instruction shortcode. For example, here are the instructions for the Performance audit:
- Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
- Click the Lighthouse tab.
- Make sure the Performance checkbox is selected in the Categories list.
- Click the Generate report button.
Labels #
Labels can be used to display a filename associated with a code snippet.
{% Label %}filename.js:{% endLabel %}
```js
console.log('hello');
```
filename.js:
console.log('hello');
Lists #
See the Lists section of the Grammar, mechanics, and usage post for information about when to use each list type.
Use standard Markdown syntax for lists: 1.
for ordered lists and -
for unordered lists.
Ordered list #
1. Lorem ipsum dolor sit amet…
1. Lorem ipsum dolor sit amet…
1. Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
Unordered list #
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
- Lorem ipsum dolor sit amet…
Definition list #
First Term
: This is the definition of the first term.
Second Term
: This is one definition of the second term.
: This is another definition of the second term.
- First Term
- This is the definition of the first term.
- Second Term
- This is one definition of the second term.
- This is another definition of the second term.
Stats #
Use the Stats component to call out important statistics about a product or service discussed in a post. (Stats are primarily used in case studies.)
Include no more than four statistics in a single Stats component to avoid layout issues.
<ul class="stats">
<div class="stats__item">
<p class="stats__figure">
30
<sub>%</sub>
</p>
<p>Lower cost per conversion</p>
</div>
<div class="stats__item">
<p class="stats__figure">
13
<sub>%</sub>
</p>
<p>Higher CTR</p>
</div>
<div class="stats__item">
<p class="stats__figure">
4
<sub>x</sub>
</p>
<p>Faster load times</p>
</div>
</ul>
30 %
Lower cost per conversion
13 %
Higher CTR
4 x
Faster load times
Stats component with applied utility class bg-state-good-bg color-state-good-text
:
30 %
Lower cost per conversion
13 %
Higher CTR
4 x
Faster load times
Tables #
Use the markup below to create a table. Do not use Markdown syntax; it doesn't include the wrapper element needed to ensure correct whitespace around the table.
<div class="table-wrapper scrollbar">
<table>
<thead>
<tr>
<th>Image Format</th>
<th>Lossy Plugin(s)</th>
</tr>
</thead>
<tbody>
<tr>
<td>JPEG</td>
<td><a href="#">imagemin-mozjpeg</a></td>
</tr>
<tr>
<td>PNG</td>
<td><a href="#">imagemin-pngquant</a></td>
</tr>
<tr>
<td>GIF</td>
<td><a href="#">imagemin-giflossy</a></td>
</tr>
</tbody>
<caption>
Imagemin plugins for filetypes.
</caption>
</table>
</div>
Network | Device | JS | Images | CSS | HTML | Fonts | Total | Time to Interactive budget |
---|---|---|---|---|---|---|---|---|
Slow 3G | Moto G4 | 100 | 30 | 10 | 10 | 20 | ~170 KB | 5s |
Slow 4G | Moto G4 | 200 | 50 | 35 | 30 | 30 | ~345 KB | 3s |
WiFi | Desktop | 300 | 250 | 50 | 50 | 100 | ~750 KB | 2s |
Tabs #
Use web-tabs
web component to display content that refers to different platforms or languages. Each child of the web-tabs
component will become a separate tab. Use data-label
attribute to set the tab's title. You can use markdown inside the tab, e.g. the code blocks.
<web-tabs>
<div data-label="html">
```html
<p>I'm html</p>
```
</div>
<div data-label="css">
```css
.class { border: 0; }
```
</div>
</web-tabs>
<p>I'm html</p>
.class { border: 0; }
Tooltips #
Use tooltips to provide information about UI controls that are too small to have a label
<div class="tooltip" data-alignment="">
<button class="fab" aria-labelledby="mytooltip">
{% include "icons/plus.svg" %}
</button>
<span class="tooltip__content" role="tooltip" id="mytooltip"
>Standard alignment</span
>
</div>
Video / YouTube #
See the Images and video post.