Tobias Uhmann
Tobias Uhmann

Reputation: 3037

Preserve whitespace between <span>s in Vue

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.

Upvotes: 12

Views: 7213

Answers (2)

santiago arizti
santiago arizti

Reputation: 4737

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.

Upvotes: 18

Tobias Uhmann
Tobias Uhmann

Reputation: 3037

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

Upvotes: 10

Related Questions