Solution 1 :

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:
            // 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';

The documentation (at the time of writting):


  • 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.

Solution 2 :

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

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> 


Solution 3 :

You can control the behavior of whitespace within an element via the white-space CSS Property or pre html element. You can opt for the pre html element in your case because you do not have any other special configuration for the white-space behavior.


Problem :

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

span {
  background-color: yellow;

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.


Comment posted by Lawrence Cherone

how are you adding the spans? the issue is in that code

Comment posted by Gaël J

You mean linebreaks?

Comment posted by santiago arizti

the OP’s concern is 100% valid, I have seen people in other forums say that “we should not rely on a framework to handle our whitespace”, but the argument is: if html preserves the whitespace, why should vue remove it?

Comment posted by…

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

Comment posted by santiago arizti

this is a workaround, as in standard html the OP’s problem is non-existent, but with vue it happens

Comment posted by McGrew

That doesn’t work with Vue, because Vue will remove the whitespace. So setting the css whitespace property doesn’t help for text that has already had the whitespace removed.