Creating user interfaces with the HTML service follows many of the same patterns and practices as other types of web development. However, there are some aspects that are unique to the Apps Script environment or are otherwise worth highlighting. Below we'll cover some best practices you should keep in mind when developing your own HTML-service UIs.
To help demonstrate these best practices, we have created a sample web app using the HTML service called Simple Tasks. The full source code and setup instructions are available in our GitHub repository.
Separate HTML, CSS, and JavaScript
Keeping all the HTML, CSS, and JavaScript code in one file can make your project
difficult to read and develop. While Apps Script does require client-side code
to be placed in .html files, you can still separate your CSS and client-side
JavaScript into different files for better readability. Separated files can be
included back into the main HTML page using template statements such as
<?!= include(myCSS); ?>.
Code.gs
function doGet(request) {
return HtmlService.createTemplateFromFile('Page')
.evaluate();
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('Stylesheet'); ?>
</head>
<body>
<h1>Welcome</h1>
<p>Please enjoy this helpful script.</p>
<?!= include('JavaScript'); ?>
</body>
</html>
Stylesheet.html
<style>
p {
color: green;
}
</style>
JavaScript.html
<script>
window.addEventListener('load', function() {
console.log('Page is loaded');
});
</script>
Notice that the Stylesheet and JavaScript files must contain the <style> and
<script> tags respectively, because they are HTML snippets and not pure
.css or .js files.
Load data asynchronously, not in templates
Templated HTML can be used to quickly build simple interfaces, but its use should be limited to ensure your UI is responsive. The code in templates is executed once when the page is loaded, and no content is sent to the client until the processing is complete. Having long-running tasks in your scriptlet code can cause your UI to appear slow.
Use scriptlet tags for quick, one-time tasks such as including other content
or setting static values. All other data should be loaded using
google.script.run calls.
Coding in this asynchronous manner is more difficult but allows the UI to load
more quickly and gives it the opportunity to present a spinner or other
loading message to the user.
Don't — load in templates
<p>List of things:</p>
<? var things = getLotsOfThings(); ?>
<ul>
<? for (var i = 0; i < things.length; i++) { ?>
<li><?= things[i] ?></li>
<? } ?>
</ul>
Do — load asynchronously
<p>List of things:</p>
<ul id="things">
<li>Loading...</li>
</ul>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(showThings)
.getLotsOfThings();
});
function showThings(things) {
var list = $('#things');
list.empty();
for (var i = 0; i < things.length; i++) {
list.append('<li>' + things[i] + '</li>');
}
}
</script>
In the Simple Tasks sample application, the HTML-service page Page.html loads data this way, and only uses templating to include other source code into the page.
Load resources using HTTPS
If your page is served using the newer IFRAME
sandbox mode, including
JavaScript or CSS files not served using HTTPS will result in errors like the
one below.
Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure script 'http://...'. This request has been blocked; the content must be served over HTTPS.
Most popular libraries support both HTTP and HTTPS, so switching is usually just a matter of inserting an addition 's' into the URL.
Use the HTML5 document type declaration
If your page is served using the newer IFRAME
sandbox mode, make sure
to include the following snippet of code at the top of you HTML file.
<!DOCTYPE html>
This document type declations tells the browser that you designed the page for modern browsers, and that it shouldn't render your page using quirks mode. Even if you don't plan to take advantage of modern HTML5 elements or JavaScript APIs, this will help ensure your page is displayed correctly.
Don't use <html>, <head>, or <body> tags
If your page is sanitized by Caja
instead of the newer IFRAME
sandbox mode, high-level
structural tags are replaced with virtual tags and your markup is inserted into
another page created by Caja. For example, an <html> tag is replaced by
<caja-v-html>. Any styles or scripts you attach to these elements are
preserved, but the semantic meaning changes.
Because of this behavior, we recommend that you don't use <html>, <head>,
or <body> tags in your page and instead just place your styles, scripts, and
other HTML content directly in the page. To set the title of your page, use the
setTitle() method
of HtmlOutput, since <title> tags in your page are ignored.
Load JavaScript last
Many web developers recommend loading JavaScript code at the bottom of the page
to increase responsiveness, and this is even more important with the HTML
service. Moving your <script> tags to the end of your page will let HTML
content render before the JavaScript is processed, allowing you to present a
spinner or other message to the user.
Take advantage of jQuery
jQuery is a popular JavaScript library that simplifies many common tasks in web development. We take special care to ensure that jQuery works with our Caja sanitization and encourage developers to leverage it in their applications.