246

In es6 template literals, how can one wrap a long template literal to multiline without creating a new line in the string?

For example, if you do this:

const text = `a very long string that just continues
and continues and continues`

Then it will create a new line symbol to the string, as interpreting it to have a new line. How can one wrap the long template literal to multiple lines without creating the newline?

Ville Miekk-oja
  • 18,749
  • 32
  • 70
  • 106
  • 5
    FWIW the line continuations are hard to read and brittle against unexpected spaces, so I prefer the Monte Jones solution over the Codingintrigue one. FWIW the Google style guide [recommends](https://google.github.io/styleguide/jsguide.html#features-strings-no-line-continuations) the Monte Jones solution and the AirBnB guide [recommends](https://github.com/airbnb/javascript#strings--line-length) just using a very long line instead--that is, neither recommends line continuations. FWIW, I couldn't find this topic in a quick check of other style guides. – Tom O'Neill Apr 05 '18 at 21:39

11 Answers11

311

If you introduce a line continuation (\) at the point of the newline in the literal, it won't create a newline on output:

const text = `a very long string that just continues\
and continues and continues`;
console.log(text); // a very long string that just continuesand continues and continues
CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
  • 1
    Not sure I understand what you mean. Can you provide a [REPL Example](https://babeljs.io/repl/)? – CodingIntrigue May 19 '16 at 11:27
  • 1
    Not easily in my case, since different variables are taken from coffeescript config files etc.. mm.. it seems that it works otherwise but for some reason it adds empty space there – Ville Miekk-oja May 19 '16 at 11:40
  • Don't know why your solution didn't work the first place, but now it started working even I didn't change anything. Thanks a lot! – Ville Miekk-oja May 19 '16 at 11:46
  • 1
    If you use a line continuation on the first line it does not works for me (node v7) – Danielo515 Feb 06 '17 at 09:47
  • 2
    If you are using this into test sometimes it doesn't return the same string. I've solved my headaches using [deline](https://github.com/airbnb/deline]) which is just a `1.1k Airbnb library` – iarroyo Mar 06 '18 at 13:08
  • 112
    This solution doesn't work nicely **with indents** (and indents are common in development). The character after the \ on the new line has to be the **first character** on that line. Meaning, the `and continues...` has to start from 0th position on the new line, breaking the indent rule. – KingJulian Apr 05 '18 at 05:50
  • I thought the whitespace retention would translate to html if placed within an element.. but it doesn't... so I guess whats the point of the whitespace retention except for development and ease of readability? – carinlynchin Apr 03 '19 at 20:35
97

This is an old one. But it came up. If you leave any spaces in the editor it will put them in there.

if
  const text = `a very long string that just continues\
  and continues and continues`;

just do the normal + symbol

if
  const text = `a very long string that just continues` +
  `and continues and continues`;
Monte Jones
  • 1,109
  • 7
  • 3
  • 7
    Good, but part of the reason I use this is to avoid the '+' symbol. It makes code harder to read and more annoying to work with. – dgo Dec 06 '19 at 19:05
  • 3
    Unfortunately this doesn't work with Tagged template literals. – nevf Jan 27 '21 at 04:56
  • 1
    Concatenation is also much slower for the newer JavaScript engines. See "UPDATE (February 2020)" section on [this StackOverflow post](https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation#:~:text=Edit%3A%20(February%202020)). – Abel Wenning Feb 09 '21 at 18:17
35

You could just eat the line breaks inside your template literal.

// Thanks to https://twitter.com/awbjs for introducing me to the idea
// here: https://esdiscuss.org/topic/multiline-template-strings-that-don-t-break-indentation

const printLongLine = continues => {
    const text = `a very long string that just ${continues}${''
                 } and ${continues} and ${continues}`;
    return text;
}
console.log(printLongLine('continues'));
Doug Coburn
  • 2,485
  • 27
  • 24
  • 10
    This is a very good hack, but it fails if you have a pretty formatter (like `prettier`) configured in your IDE. `prettier` wraps this up back to single line. – Rvy Pandey Sep 10 '19 at 20:49
28

Another option is to use Array.join, like so:

[
    'This is a very long string. ',
    'It just keeps going ',
    'and going ',
    'and going ',
    'and going ',
    'and going ',
    'and going ',
    'and going',
].join('')
Liran H
  • 9,143
  • 7
  • 39
  • 52
14

EDIT: I've made an tiny NPM module with this utility. It works on web and in Node and I highly recommend it over the code in my below answer as it's far more robust. It also allows for preserving newlines in the result if you manually input them as \n, and provides functions for when you already use template literal tags for something else: https://github.com/iansan5653/compress-tag


I know I'm late to answer here, but the accepted answer still has the drawback of not allowing indents after the line break, which means you still can't write very nice-looking code just by escaping newlines.

Instead, why not use a tagged template literal function?

function noWhiteSpace(strings, ...placeholders) {
  // Build the string as normal, combining all the strings and placeholders:
  let withSpace = strings.reduce((result, string, i) => (result + placeholders[i - 1] + string));
  let withoutSpace = withSpace.replace(/\s\s+/g, ' ');
  return withoutSpace;
}

Then you can just tag any template literal you want to have line breaks in:

let myString = noWhiteSpace`This is a really long string, that needs to wrap over
    several lines. With a normal template literal you can't do that, but you can 
    use a template literal tag to allow line breaks and indents.`;

This does have the drawback of possibly having unexpected behavior if a future developer isn't used to the tagged template syntax or if you don't use a descriptive function name, but it feels like the cleanest solution for now.

Ian
  • 5,704
  • 6
  • 40
  • 72
8

Use the old and the new. Template literals are great but if you want to avoid lengthy literals so as to have compact lines of code, concatenate them and ESLint won't cause a fuss.

const text = `a very long string that just continues`
  +` and continues and continues`;
console.log(text);
Wachaga Mwaura
  • 3,310
  • 3
  • 28
  • 31
3

Similar to Doug's answer this is accepted by my TSLint config and remains untouched by my IntelliJ auto-formatter:

const text = `a very long string that just ${
  continues
} and ${continues} and ${continues}`
Daniel K
  • 2,977
  • 2
  • 24
  • 23
2

this npm package allows you to do the following...

import { oneLine } from 'common-tags';

const foo = oneLine`foo
bar
baz`;

console.log(foo); // foo bar baz
shunryu111
  • 5,895
  • 4
  • 27
  • 16
1

The solution proposed by @CodingIntrigue is not working for me on node 7. Well, it works if I do not use a line continuation on the first line, it fails otherwise.

This is probably not the best solution, but it works without problems:

(`
    border:1px solid blue;
    border-radius:10px;
    padding: 14px 25px;
    text-decoration:none;
    display: inline-block;
    text-align: center;`).replace(/\n/g,'').trim();
Danielo515
  • 5,996
  • 4
  • 32
  • 66
1

I'm a bit late to the party, but for any future visits on this question, I found this soultion the most optimal for my use case.

I'm running a Node.js server and wanted to return html in string format, this is how I solved it:


My response object:

const httpResponse = {
    message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices et odio eget blandit. Donec non tellus diam. Duis massa augue, cursus a ornare vel, pharetra ac turpis.',
    html: `
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <p>Praesent ultrices et odio eget blandit.</p>
        <ul>
            <li>Donec non tellus diam</li>
            <li>Duis massa augue</li>
        </ul>
    `,
}

This would translate into the following when sending a http request:

{
    "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices et odio eget blandit. Donec non tellus diam. Duis massa augue, cursus a ornare vel, pharetra ac turpis.",
    "html": "\n\t\t<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>\n\t\t<p>Praesent ultrices et odio eget blandit.</p>\n\t\t<ul>\n\t\t\t<li>Donec non tellus diam</li>\n\t\t\t<li>Duis massa augue</li>\n\t\t</ul>\n\t"
}

This is of course ugly and hard to work with. So before I sending the http I trim every line of the string.

httpResponse.html = httpResponse.html.split('\n').map(line => line.trim()).join('')

This is what the result looks like after that simple line of code.

{
    "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices et odio eget blandit. Donec non tellus diam. Duis massa augue, cursus a ornare vel, pharetra ac turpis.",
    "html": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p><p>Praesent ultrices et odio eget blandit.</p><ul><li>Donec non tellus diam</li><li>Duis massa augue</li></ul>"
}
Jonathan Nielsen
  • 1,442
  • 1
  • 17
  • 31
0

If your problem is the opposite and you need to keep the line breaks but for some reason, they are not being respected, just add the css property in the text container:

#yourTextContainer {
  white-space: pre-line;
}
Juanma Menendez
  • 17,253
  • 7
  • 59
  • 56