Skip to content
aviral gupta

// B2.3 · ~30 min · Beginner

Strings and template literals

After this lesson you can write any text as a JavaScript string, pick characters and pieces out of it, tidy it with string methods, and build messages with template literals.

Lesson 3 of 5 in B2 Grammar, types and operators

You will be able to

  • Write strings with quotes and escapes, and read their length and characters by index
  • Use slice, includes, startsWith, toUpperCase, trim and padStart, knowing that each returns a new string
  • Build text with template literals: ${} placeholders and text over several lines
  1. Warm-up · Activity 1 of 7

    Warm-up: which of these is a valid string holding the text It’s fine (with a straight apostrophe)?

  2. Predict · Activity 2 of 7

    Predict before you read on: what does this print?

    const word = "hello";
    word.toUpperCase();
    console.log(word);
  3. Practice · Activity 3 of 7

    Fill in the number so that the program prints Java.

    console.log("JavaScript".slice(0, ____));
    console.log("JavaScript".slice(0, ));
  4. Practice · Activity 4 of 7

    Match each expression to what console.log prints for it.

  5. Practice · Activity 5 of 7

    What does this print?

    console.log("Banana".includes("ban"));
  6. Brain teaser · Activity 6 of 7

    Brain teaser. What does this print?

    console.log("Total: ${2 + 3}");
  7. Apply · Activity 7 of 7

    Mini-task. A till gives you the item " coffee " (with stray spaces), a quantity of 2, a price of 3.2 and the order number 42. Using template literals, print COFFEE x2, then Total: 6.40 EUR, then Order no. 00042.

    Check your work against this list

Build it yourself

Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.

Worked example

Printing a train ticket

A booking form sends a passenger name with stray spaces and in lower case. This program tidies it, picks characters and pieces out of it, checks the station name, and prints a three-line ticket with one template literal. Run it, then change the seat to 12 and the name to your own.

main.js

// Formatting a train ticket from raw text.
const rawName = "  ada lovelace ";
const from = "Berlin Hbf";
const seat = 7;
const name = rawName.trim();
console.log("name:", name, "length:", name.length);
console.log("initial:", name[0].toUpperCase());
console.log("first name:", name.slice(0, 3));
console.log("from Berlin?", from.startsWith("Berlin"), "main station?", from.includes("Hbf"));
const ticket = `Passenger: ${name.toUpperCase()}
From: ${from}
Seat: ${String(seat).padStart(3, "0")}`;
console.log(ticket);
console.log('She said "bon voyage"\nand waved.');
console.log("rawName is unchanged:", rawName.length);

Run it with

node main.js

Output

name: ada lovelace length: 12
initial: A
first name: ada
from Berlin? true main station? true
Passenger: ADA LOVELACE
From: Berlin Hbf
Seat: 007
She said "bon voyage"
and waved.
rawName is unchanged: 15
  • trim() returns a new string without the spaces at the ends: 12 characters instead of 15.
  • name[0] is the first character; toUpperCase() makes a capital A from it.
  • slice(0, 3) takes indexes 0, 1 and 2: ada.
  • The template literal spans three lines, so one console.log prints the whole ticket.
  • Single quotes let the text contain double quotes, and \n starts a new line.
  • rawName still has its 15 characters: no method changed it.
Change it and run it

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Exercises

Exercise 1 of 2

Tidy a name

A form sends the name " Grace Hopper " with stray spaces. Print three lines: Hello, Grace Hopper! (without the extra spaces), Letters: 12 (the length of the tidied name, space included) and Code: GRA (its first three characters in upper case). Work every value out from raw.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    raw.trim() returns the name without the spaces at both ends. Store it: const name = raw.trim();

  2. Hint 2

    name.length counts the characters, the space in the middle too.

  3. Hint 3

    name.slice(0, 3) gives "Gra"; call toUpperCase() on that result.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

const raw = "   Grace Hopper  ";
const name = raw.trim();
console.log(`Hello, ${name}!`);
console.log("Letters:", name.length);
console.log("Code:", name.slice(0, 3).toUpperCase());
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

const raw = "   Grace Hopper  ";
// Print three lines:
// Hello, Grace Hopper!
// Letters: 12
// Code: GRA
console.log("Hello, " + raw + "!");

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';

const lines = async () => (await runMain()).trimEnd().split('\n');

test('greets the tidied name', async () => {
  const got = await lines();
  assert.equal(got[0], 'Hello, Grace Hopper!', `the first line is ${JSON.stringify(got[0])}, expected "Hello, Grace Hopper!"`);
});

test('prints the length of the tidied name', async () => {
  const got = await lines();
  assert.equal(got[1], 'Letters: 12', `the second line is ${JSON.stringify(got[1])}, expected "Letters: 12"`);
});

test('prints the code in upper case', async () => {
  const got = await lines();
  assert.equal(got[2], 'Code: GRA', `the third line is ${JSON.stringify(got[2])}, expected "Code: GRA"`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Exercise 2 of 2

A parcel label

Print a parcel label of three lines with one console.log and one template literal: Order #00042 (the order number padded to five digits with zeros), To: HAMBURG (the city in upper case) and Items: 3. Use the three constants; the starter prints only Order #42.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    padStart is a string method, so turn the number into a string first: String(order).padStart(5, "0").

  2. Hint 2

    Inside backticks, press Enter where a new line should start; the line break becomes part of the text.

  3. Hint 3

    Each value goes into its own placeholder: ${city.toUpperCase()}.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

const order = 42;
const city = "Hamburg";
const items = 3;
console.log(`Order #${String(order).padStart(5, "0")}
To: ${city.toUpperCase()}
Items: ${items}`);
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

const order = 42;
const city = "Hamburg";
const items = 3;
// Print, with one template literal over three lines:
// Order #00042
// To: HAMBURG
// Items: 3
console.log("Order #" + order);

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';

const lines = async () => (await runMain()).trimEnd().split('\n');

test('pads the order number', async () => {
  const got = await lines();
  assert.equal(got[0], 'Order #00042', `the first line is ${JSON.stringify(got[0])}, expected "Order #00042"`);
});

test('prints the city in upper case', async () => {
  const got = await lines();
  assert.equal(got[1], 'To: HAMBURG', `the second line is ${JSON.stringify(got[1])}, expected "To: HAMBURG"`);
});

test('prints the number of items', async () => {
  const got = await lines();
  assert.equal(got[2], 'Items: 3', `the third line is ${JSON.stringify(got[2])}, expected "Items: 3"`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Common mistakes

Changing one character of a string

const word = "cat";
word[0] = "b";
console.log(word);

What Node.js prints

TypeError: Cannot assign to read only property '0' of string 'cat'

Why, and the fix

Strings are immutable, so their characters cannot be assigned. In a module, which is what main.js is here, this stops the program; in older scripts the line is silently ignored, which is worse. Build a new string instead: const fixed = "b" + word.slice(1); gives "bat".

The same quote inside the string

console.log('It's fine');

What Node.js prints

SyntaxError: missing ) after argument list

Why, and the fix

The apostrophe in It's ends the single-quoted string after It, so JavaScript reads s fine' as code and cannot make sense of it. Nothing in the file runs. Use double quotes, "It's fine", escape the apostrophe with a backslash, 'It\'s fine', or use backticks.

A method name with the wrong case

const name = "ada";
console.log(name.toUppercase());

What Node.js prints

TypeError: name.toUppercase is not a function

Why, and the fix

Method names are case-sensitive, and the method is toUpperCase, with a capital C. name.toUppercase does not exist, so it is undefined, and calling undefined is a TypeError. The same trap waits in toLowerCase and padStart: every word after the first starts with a capital.

JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source

Exit ticket

5 questions, no hints. Score 80% or more to complete the lesson.

Finish every activity above to unlock the exit ticket.

Report a problem

Spotted something wrong or unclear? Say what, and it will be checked and fixed.

#

At least 20 characters.

Only if you want a reply.

Key ideas

Quotes, escapes and indexes

A string goes in double or single quotes; both mean the same. To use the same quote inside, put a backslash before it: "She said \"hi\"". Or pick the other kind: "It's fine". The backslash starts an escape: \n is a new line and \\ is one backslash. A string’s length is its number of characters: "Hello".length is 5. Each character has an index, starting at 0, so "Hello"[0] is "H" and the last one is at length - 1. An index past the end gives undefined, not an error.

Methods return new strings

s.slice(0, 4) gives the characters from index 0 up to, but not including, index 4; s.slice(-3) gives the last three. s.includes("ab") and s.startsWith("ab") answer true or false, and they are case-sensitive. s.toUpperCase() and s.toLowerCase() change case, s.trim() removes spaces at both ends, and "7".padStart(3, "0") fills to "007". Strings are immutable: no method changes the string it is called on. Each one returns a new string, so name.toUpperCase(); on its own line changes nothing. Keep the result: const loud = name.toUpperCase();.

Template literals: `${}` and several lines

A template literal is a string in backticks, `like this`. Inside it, ${…} runs any expression and puts its result into the text: `Total: ${price * qty} EUR`. That is easier to read than joining pieces with +, and there is no forgotten space. The placeholder works only in backticks: "Total: ${price}" in normal quotes prints the dollar sign and braces as they are. A template literal may also continue over several lines, and every line break you type becomes part of the string, so one console.log can print a whole label.

Sources

Last reviewed September 30, 2026