8

In my Vue 3 app, I want to highlight words in a text, such as in the following HTML:

span {
  background-color: yellow;
}
<span>foo</span> 
<span>bar</span> 
baz 
qux

However, Vue removes the whitespace between tags, so the gaps between the <span>s disappear:

span {
    background-color: yellow;
}
<span>foo</span><span>bar</span> baz qux

How can I preserve the whitespace between the <span>s? I cannot use &nbsp; as the spaces should break and none of the other white space entities has the same size as a usual space.

Tobias Uhmann
  • 2,757
  • 2
  • 25
  • 35

2 Answers2

12

IMO this is totally a bug, because:

  1. native html behaves in a different way.
  2. the documentation the behaviour should default to preserving the whitespace.
  3. vue 2 didn't have this problem.

There is a vue compilerOptions option called whitespace that according to the documentation should default to 'preserve', but it does not.

To set it to 'preserve' in webpack use this config:

{
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
        compilerOptions: {
            // preserve is supposed to be the default
            // see: https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler#options
            // but as of 2022-01-13 (vue 3.2.26)
            whitespace: 'preserve',
        },
    },
},

Or if you are rendering your components on the fly (with dom templates) use this:

const app = Vue.createApp({...});
app.config.compilerOptions.whitespace = 'preserve';
app.mount('#app');

The documentation (at the time of writting):

whitespace

  • Type: string
  • Valid values: 'preserve' | 'condense'
  • Default: 'preserve'

The default value 'preserve' handles whitespaces as follows:

  • A whitespace-only text node between element tags is condensed into a single space.
  • All other whitespaces are preserved as-is.

If set to 'condense':

  • A whitespace-only text node between element tags is removed if it contains new lines. Otherwise, it is condensed into a single space.
  • Consecutive whitespaces inside a non-whitespace-only text node are condensed into a single space.

Using condense mode will result in smaller compiled code size and slightly improved performance. However, it will produce minor visual layout differences compared to plain HTML in certain cases.

santiago arizti
  • 4,175
  • 3
  • 37
  • 50
  • 3
    I might have referenced the documentation for vue 2, I cannot find the compilerOptions document for vue 3, but here in this commit they added the whitespace feature to vue 3 and defaulted to `'condense'` https://github.com/vuejs/vue-next/pull/1600/commits/1c42f3a37db3e1da19653d8294c30f251ea16bc8 – santiago arizti Jan 14 '22 at 03:37
6

Okay, so apparently, I'm not the first one to stumble across that behavior, which I would name a bug:

https://github.com/vuejs/vue-next/pull/1600

By default, Vue removes whitespace between elements for compression purposes - other than browsers, which reduce such whitespace to a single space. In Vue 2 it was possible to change the config to preserve whitespace. In Vue 3 this is not possible (yet).

However, there are some workarounds and as mentioned in a comment [1], whitespace is only removed if it contains linebreaks. Therefore, by removing the linebreaks in the above example's source code, the snippet behaves as expected:

<span>foo</span> <span>bar</span> 
baz
qux

[1] https://github.com/vuejs/vue-next/pull/1600#issuecomment-747162894

Tobias Uhmann
  • 2,757
  • 2
  • 25
  • 35