Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better whitespace handling #189

Closed
Rich-Harris opened this issue Dec 11, 2016 · 66 comments
Closed

Better whitespace handling #189

Rich-Harris opened this issue Dec 11, 2016 · 66 comments
Labels
compiler Changes relating to the compiler feature request
Milestone

Comments

@Rich-Harris
Copy link
Member

While fixing #178 it occurred to me that there are some nodes, like <datalist>, where it doesn't make sense to have text node children. The browser agrees:

document.body.innerHTML = `
  <div>
    <span>a</span>
    <span>b</span>
  </div>
`;

console.log( document.body.querySelector( 'div' ).childNodes );
// [ text, span, text, span, text ]

document.body.innerHTML = `
  <datalist>
    <option value='a'/>
    <option value='b'/>
  </datalist>
`;

console.log( document.body.querySelector( 'datalist' ).childNodes );
// [ text, option, option ]

Not sure what the first text node is doing there in the second case. Anyway, Svelte should be smart enough not to create text nodes inside elements where they're meaningless.

Additionally, we could collapse excess whitespace between nodes that aren't inside a <pre> element, since these are equivalent:

<p>one</p> <p>two</p>
<p>  one  </p>

    <p>  two  </p>

(That's not strictly true, since it's dependent on CSS, so there probably needs to be a preserveWhitespace: true option if we did that.)

@Swatinem
Copy link
Member

I personally would like to avoid all inter-element whitespace as much as possible.

Maybe do something similar to pug and jsx (at least I think thats what it does),
where whitespace is only added if the elements are on the same line (inline).
Tags with newlines in between get that whitespace stripped completely.

Pug even has special syntax for inline tags: https://pugjs.org/language/interpolation.html

So for example:

<ul>
  <li>
    Some <strong>inline</strong> tags.
  </li>
</ul>

would generate the following html:

<ul><li>Some <strong>inline</strong> tags.</li></ul>

@Rich-Harris
Copy link
Member Author

That actually happens already – whitespace inside either end of an element is removed: https://svelte.technology/repl/?gist=f4657520185203c009a9116568ac5ba2

The problems start when you have siblings separated by newlines:

<ul>
  <li>
    Some
    <strong>inline</strong>
    <em>newline separated</em>
    tags.
  </li>
</ul>

In that case you can't remove whitespace before the <strong>, or between the <strong> and the <em>, or after the <em>. You could collapse the intermediate whitespace to a single space character and it would behave identically (assuming no white-space: pre CSS or similar), but you can't remove it. You can probably remove it if the elements are block-level, but it's unsafe because it depends on display: block.

@Swatinem
Copy link
Member

I thought about using a whitelist of inline elements as well, but I don’t think that’s a good idea. I rather think we should do the same as react/jsx and pug do here and remove all whitespace when elements are on a newline.
If you explicitly want to have it on a newline, one could render the text as an explicit snippet <span>{{" like so, with whitespace "}}</span>. I have seen this pattern a few times in react codebases, although I admit its ugly.

@Rich-Harris
Copy link
Member Author

Trouble is pug and JSX are different languages, so they can get away with different semantics. Svelte templates are just HTML (plus tags, blocks and directives), so from the user's perspective if markup behaves differently then it's a bug. Maybe it could be an opt-in thing? whitespace: 'aggressive' or something?

If we do collapse whitespace to a single character, then when we get round to implementing helpers it won't be quite so bad:

// instead of this...
var text4 = document.createTextNode( '\n\t\t\t' );

// ...this
var text4 = whitespace();

@Swatinem
Copy link
Member

Its really a question what the user expects I guess… More often things are breaking because of unintended whitespace. And depending on the users background, they might be used to template system that have a more aggressive whitespace handling.

@Ryuno-Ki
Copy link

@Rich-Harris wrote;

Not sure what the first text node is doing there in the second case.

I'm quite sure it is a line break.

Django and Twig have a spaceless environment tag.

@Conduitry
Copy link
Member

What I'm currently doing is sending my templates through https://github.com/kangax/html-minifier before sending them through svelte -

HTMLMinifier.minify(html, {
	caseSensitive: true,
	collapseWhitespace: true,
	conservativeCollapse: true,
	ignoreCustomFragments: [ /{{[^]*?}}/ ],
	keepClosingSlash: true,
})

which seems to work well enough. conservativeCollapse makes runs of whitespace get collapsed down to one space instead of zero. caseSensitive and keepClosingSlash are necessary to keep svelte happy with the template. And ignoreCustomFragments is necessary to keep html-minifier from trying to parse tags.

@camwest
Copy link

camwest commented Jan 11, 2017

I think if you look at the HTML 5 spec they have an interesting way of handling this. You can have different insertion modes where character tokens are handled differently. See "in-select" insertion mode for example: https://www.w3.org/TR/html5/syntax.html#parsing-main-inselect

@cristinecula
Copy link
Contributor

Removing whitespace between tags is important for layouts using display: inline-block.

I agree that preserving the HTML expectations is important, so I think that whitespace removal should be explicit. As @Ryuno-Ki mentioned, the Twig spaceless tag is a great solution.

{% spaceless %}
    <div>
        <strong>foo</strong>
    </div>
{% endspaceless %}

{# output will be <div><strong>foo</strong></div> #}

@PaulBGD
Copy link
Member

PaulBGD commented Mar 28, 2017

Could we do something like

export default {
  keepWhitespace: true
}

then check that at compile time?

@mrkishi
Copy link
Member

mrkishi commented Jan 22, 2018

It seems we can no longer naively pass Svelte components through html-minifier because of the new Svelte-specific tags (eg. <:Head>).

Does anyone have a workaround for that?

@Conduitry
Copy link
Member

My comment here could probably be extended to use ignoreCustomFragments to also ignore <:Head>. Another regex could be added, something like /<:Head>[^]*?<\/:Head>/. I'm no longer using the method from that comment, however, so I haven't tried this.

@adamhooper
Copy link

First time user, obvious question: why not just copy React?

@Rich-Harris referring back to a comment you made in 2016:

Svelte templates are just HTML (plus tags, blocks and directives), so from the user's perspective if markup behaves differently then it's a bug.

I'm skeptical -- maybe because other frameworks have changed my expectations. I'm new to Svelte (and love it): I think of it as a transpiler. I don't feel I'm writing HTML: I feel I'm writing JavaScript with an abundance of < and > characters.

When I first used React (very recently), I had no preconceptions about whitespace. I learned to my delight that JSX is not HTML.

And now I've just learned Svelte, and I see myself writing huge statements on one line. Here's code from my second-ever Svelte component, which happens to use the dreaded <pre> tag:

<pre ref:pre class={{wrapText ? 'wrap' : ''}}>{{#each plainAndHighlightedPairs as [ plain, highlighted ], i}}{{plain}}{{#if highlighted}}<em class={{highlightIndex === i ? 'current' : ''}}>{{highlighted}}</em>{{/if}}{{/each}}</pre>

Svelte is getting in the way. Can that line be sensible?

If Svelte followed React's whitespace rules, it would be legible:

<pre ref:pre class={{wrapText ? 'wrap' : ''}}>
  {{#each plainAndHighlightedPairs as [ plain, highlighted ], i}}
    {{plain}}
    {{#if highlighted}}
      <em class={{highlightIndex === i ? 'current' : ''}}>{{highlighted}}</em>
    {{/if}}
  {{/each}}
</pre>

Svelte's choice is between "pretend to be HTML" and "pretend to be easy." They're mutually exclusive. People choose Svelte because HTML is too complicated: it could be easier here. And yes, changing whitespace rules is backwards-incompatible; but hey, React did it.

This is an awfully long comment, so I'll finish with a rhetorical flourish: can any reader here describe HTML's whitespace rules from memory?

@Rich-Harris
Copy link
Member Author

Just rediscovered this issue via #1236. @adamhooper you make a strong case; the <pre> example is gnarly. I have a counter-example though — I see this sort of thing a lot in React codebases:

<p>
  click
  {' '}
  <a href={`/foo/${this.props.bar}`}>here</a>
  {' '}
  for more information
</p>

The Svelte/HTML equivalent:

<p>
  click
  <a href='/foo/{{bar}}'>here</a>
  for more information
</p>

Having to insert {' '} in order to preserve spaces around the <a> is utterly grotesque, and I'd argue that the JSX rules (whitespace is significant unless it happens to contain a newline) are ultimately no more intuitive than HTML rules.

Not suggesting that we have to comply strictly with HTML, just that we need to weigh up the consequences of deviating from it.

@morleytatro
Copy link

I agree with @adamhooper on this and would love to see Svelte's HTML output with collapsed whitespace as React does it. Things like inline-block menus, tab headers, and breadcrumbs become a big mess of code when you want the whitespace eliminated. For example:

<ul class="breadcrumbs">
{#each breadcrumbs as item, i}<li>{#if i !== breadcrumbs.length - 1}<a href="{item.url}">{item.title}</a>{:else}{item.title}{/if}</li>{/each}
</ul>

@lydell
Copy link

lydell commented Apr 24, 2019

Having to insert {' '} [in JSX] in order to preserve spaces around the <a> is utterly grotesque

I type it out all on one line and then let Prettier do the {' '} for me ¯\_(ツ)_/¯

@tomblachut
Copy link

Angular has similar feature of removing whitespaces.
https://angular.io/api/core/Component#preserving-whitespace

Key takeaways:

  • ngPreserveWhitespaces directive that affects whole element subtree can be applied
  • To force single space, use &ngsp; entity - that's certainly better than {' '}
  • There's also global and per component flag preserveWhitespace. I see that's it's supported already in Svelte
  • collapse consecutive whitespace characters #2258 says that <pre> tags are handled specially. Angular documentation also mentions <textarea> and more tags (if any) could be looked up in their repo.

I'd like to note that as a longtime user of Angular I never had problems stemming from this particular feature. It's enabled by default and optimises generated code a lot. Behaviour becomes natural like export let for props and on rare occasion if something doesn't look right you notice it during development and apply appropriate override.

@steve-taylor
Copy link

Having to insert {' '} in order to preserve spaces around the <a> is utterly grotesque

Spaces between elements seems to be the exception rather than the rule, so you don't see too much {' '}.

I'd argue that the JSX rules (whitespace is significant unless it happens to contain a newline) are ultimately no more intuitive than HTML rules.

They're very intuitive. I've been caught out many times by extraneous spaces between and within HTML elements. I've had no such surprises with JSX.

@kylecordes
Copy link

It looks like this one is still heavily under discussion. I can echo @tomblachut 's experience from Angular. What Angular does "just works" for almost all cases, producing efficient output by default. "Efficient by default" is an important trade-off against what @Rich-Harris mentioned earlier, behaving as much as possible like ordinary HTML by default.

Every once in a while it causes trouble - rarely enough that switching to "preserve whitespace" for a subtree or entire component fixes it easily with only a tiny impact on an overall applications compiled output size.

@frederikhors
Copy link

I saw this but I'm asking if this is the same for my problem: #2745

@dummdidumm dummdidumm added this to the 5.x milestone Nov 13, 2023
@kevincox
Copy link

kevincox commented Nov 13, 2023

Can "Whitespace at the start and end of a tag is removed completely" be clarified? Or is there a reference somewhere?

It isn't clear to me if it is talking about all around the start and end of a tag, or just inside of the tag. For example:

<foo>
  <bar></bar>
  <bar> </bar>
</foo>

Is this equivalent to A, where all whitespace around tags is removed.

<foo><bar></bar><bar></bar></foo>

Or B where only the whitespace inside of start and end tags are removed.

<foo><bar></bar> <bar></bar></foo>

@justingolden21
Copy link

justingolden21 commented Nov 13, 2023

Thank for the reply @dummdidumm ! I understand the problem now. Not sure about the solution other than using prettier-ignore and dealing with a long line or two.

In my specific use case, I'm just using a pipe | separator anyway now 😅

But it's good knowledge to have for the future when I come across this again! Thanks again 😄

@dummdidumm
Copy link
Member

@kevincox it would be B. Whitespace between tag siblings is trimmed to one whitespace.

@nilslindemann
Copy link

nilslindemann commented Nov 14, 2023

@dummdidumm there: It is not practical to always collapse whitespace between nodes to one white space. This will not resolve the main problem. If you do it this way, you can as well do nothing, because the browser anyway takes care of this type of whitespace folding.

The relevant question is how to handle whitespace between elements. Consider my post above, how Fresh does it:

  1. If a newline is contained, then all white spaces are removed
  2. otherwise, the white spaces are collapsed to one whitespace
  3. white space after opening tag and before closing tag is all removed (which you intend to do)

Example for 1

<foo/>

{#if hi}

<bar/>

Hello

<baz/>

{/if}

Hello

<quux/>

becomes

<foo/>{#if hi}<bar/>Hello<baz/>{/if}Hello<quux/>

Example for 2

<foo/>   {#if hi}   <bar/>   Hello   <baz/>   {/if}   Hello   <quux/>

becomes

<foo/> {#if hi}<bar/> Hello <baz/>{/if} Hello <quux/>

If the user wants to insert explicit whitespace, he uses {" "}. That method is also used inside pres, no special handling for them.

{...} blocks behave like element tags

White space between text and elements is handled the same way. Remove all of it when a newline is contained, otherwise collapse it to one whitespace.

@dummdidumm
Copy link
Member

To be honest, everyone makes up their own set of slightly different arbitrary rules. We picked this specific ruleset to be as much backwards-compatible as possible with Svelte 4 while making things easier to reason about. There's no correct answer here.

@nilslindemann
Copy link

@dummdidumm Your solution is just bad. The user will not be able to format his code intuitively without having unwanted whitespaces.

<ul>
    <li>Homepage</li>
    <li>Docs</li>
    <li>Blog</li>
</ul>

Will not become

<ul><li>Homepage</li><li>Docs</li><li>Blog</li></ul>

as it should. It will become

<ul><li>Homepage</li> <li>Docs</li> <li>Blog</li></ul>

And every CSS designer will curse.

@nilslindemann
Copy link

nilslindemann commented Nov 14, 2023

The implementation of my solution is not difficult, you search for [^\S\n]*(\n)?\s* and if you have a match for (\n) you replace with the empty string, otherwise, if you matched anything, with one white space. (Edit: I changed the regex, so, admittedly, it is not super trivial)

@nilslindemann
Copy link

But ok, I've raised my objections, now it's up to the developers.

@nilslindemann
Copy link

nilslindemann commented Nov 14, 2023

Here is a minimal grammar for Peggy.

/*
HTML parser with nice whitespace handling.
Just the minimal stuff implemented, to explain the idea.
*/

Document = IgnoreWS @Node IgnoreWS

Node = Elem / Text

Text =
    first: Word
    rest: (
        ws: CollapseWS
        word: Word { return ws + word }
    )* { return first + rest.join('') }

Word = $([^<> \t\r\n]+)

Elem =
    opentag: Opentag
    content: (
        first: Node
        rest: (
            ws: DecideWS
            node: Node { return ws + node }
        )* { return first + rest.join('') }
    )
    closetag: Closetag { return opentag + content + closetag }

Opentag =
    opentag: (
        @"<"
        IgnoreWS
        @Tagname
        IgnoreWS
        @">"
        IgnoreWS
    ) { return opentag.join('') }

Closetag =
    closetag: (
        IgnoreWS
        @"<"
        IgnoreWS
        @"/"
        IgnoreWS
        @Tagname
        IgnoreWS
        @">"
    ) { return closetag.join('') }

Tagname =
    $([a-z] [a-z0-9]*)

CollapseWS =
    ([ \t\r\n]+) {return ' '}

IgnoreWS =
    ([ \t\r\n]*) {return ''}

DecideWS =
    WSwithNewline / CollapseWS

WSwithNewline =
    [ \t\r]*
    "\n"
    [ \t\r\n]* { return '' }

Run this e.g. on ...

<ul>
    <li>
        lorem
        ipsum <span>foo </span> dolor
    </li>
    <li>   Docs</li>
    <li>Blog   </li>
</ul>

... and you get ...

<ul><li>lorem ipsum <span>foo</span> dolor</li><li>Docs</li><li>Blog</li></ul>
  • Whitespace after opening and before closing tags is removed
  • Whitespace between words is collapsed to one
  • inline Whitespace between words and elements and between elements is collapsed to one
  • whitespace between words and elements and between elements which contains a newline is removed.

Of course a few things are missing, it is just to show the basic idea.

@dummdidumm
Copy link
Member

The user will not be able to format his code intuitively without having unwanted whitespaces.

In the case of ul/li that might be the case, but when you have this

<h1>
   <span>Hello</span>
  <bold>everyone</bold>
  <span>outside</span>
</h1>

You can Hello everyone outside and not Helloeveryoneoutside.
That's why I said that there's no perfect solution that fits for all cases. And since the new mechanism is closer to what Svelte already does and therefore is less of a breaking change, we chose that one as opposed to the "newline means drop it completely" rule.

@patricknelson
Copy link

patricknelson commented Nov 15, 2023

This might be a good situation where adherence to web standards (as much as possible, at least) would be highly advisable. Particularly when dealing with i18n and where you're encountering not only various contexts (e.g. inline vs. block) and adjacencies but also directionality (e.g. left to right vs. right to left and etc). Seems complicated to reinvent.

Here's what I found:

Here's what ChatGPT summarized for me (so take with grain of salt!):


HTML, as defined by the W3C, has rules for whitespace handling, and these rules are generally consistent across elements. Here are some key points:

  1. Collapsing Whitespace:

    • Multiple consecutive whitespace characters, including spaces, tabs, and line breaks, are treated as a single space when rendering the content.
  2. Leading and Trailing Whitespace:

    • Leading and trailing whitespace within an element's content is typically ignored.
  3. Whitespace within Inline Elements:

    • Whitespace within inline elements (e.g., <span>, <a>) is generally preserved.
  4. Whitespace within Block-level Elements:

    • Whitespace within block-level elements (e.g., <div>, <p>) is usually collapsed, similar to how it is for inline elements.
  5. Preformatted Text:

    • The <pre> element is an exception; it preserves whitespace, and text is displayed in a fixed-width font.

@nilslindemann
Copy link

@dummdidumm

The user will not be able to format his code intuitively without having unwanted whitespaces.

In the case of ul/li that might be the case, but when you have this

<h1>
   <span>Hello</span>
  <bold>everyone</bold>
  <span>outside</span>
</h1>

You can Hello everyone outside and not Helloeveryoneoutside.

Your example is the much less common use case. When was the last time, where you actually wrote inline spans like a block element in different lines? You can do two things:

<h1><span>Hello</span> <bold>everyone</bold> <span>outside</span></h1>
<h1>
    <span>Hello</span>{" "}
    <bold>everyone</bold>{" "}
    <span>outside</span>
</h1>

Further, it is easy to add an option in my above grammar to switch between your model and mine. At the top of the grammar, add:

{ let strict = false }

and replace the return block in the WSwithNewline rule with:

{ return strict ? '' : ' ' }

Now, if strict is false, you get <h1><span>Hello</span> <bold>everyone</bold> <span>outside</span></h1> (your way) and otherwise you get <h1><span>Hello</span><bold>everyone</bold><span>outside</span></h1> (my way).

Now you have an option for users to set.


@patricknelson The W3Cs model is made for all kind of people, like writers. Often they do not care about specific whitespace rules. But this here are developers, and they want to have full control. If we stick to W3C rules, we can as well do nothing.

@benmccann benmccann modified the milestones: 5.x, 5.0 Nov 17, 2023
@GauBen
Copy link
Contributor

GauBen commented Nov 27, 2023

Hey there, can Svelte 5 preserve whitespace of slotted content? This is really useful for components that transform their content into rich HTML (e.g. syntax highlighting, diagrams...)

v4 vs v5

@nilslindemann
Copy link

nilslindemann commented Nov 27, 2023

@GauBen try this:

<Child>{
`a
  b
    c
      d`
}</Child>

@johanbissemattsson
Copy link

johanbissemattsson commented Jan 31, 2024

We recently encountered this issue when creating a recursive component for rendering a rich text format, where unwanted spaces where added between rendered sibling elements. We have a temporary workaround using a preprocessor which inlines the elements by simply removing tabs and new-lines in the template code but it feels rather blunt in it's current form.

I would love to be able to control this when rendering snippets in Svelte 5.

Something similar to this (the options parameter could also support other compiler options):
{@render decoratedData(data, { trimSiblingWhitespaces: true })}

I also think it's reasonable to keep the default as it is today to adhere the web standards.

@justinburrow
Copy link

Wanted to also jump in after a fair amount of google struggle led me here, because text formatting using span tags broken into new lines was creating unintended spaces.

<span class="superlongClassnameBecauseTailwind">First</span>
<span class="moreIncrediblyLongClassnamesBecauseTailwindStrikesAgain">Name</span>

...gives me First Name, instead of the expected FirstName, and in this case, with many Tailwind classes on sibling span tags, the only option here is to run them all on the same line.

I agree with the previously mentioned unordered list example:

<ul>
    <li>Homepage</li>
    <li>Docs</li>
    <li>Blog</li>
</ul>

Will not become

<ul><li>Homepage</li><li>Docs</li><li>Blog</li></ul>

as it should. It will become

<ul><li>Homepage</li> <li>Docs</li> <li>Blog</li></ul>

...being another demonstration of this behavior causing CSS headaches that I would not expect to have.

I don't personally have much of a preference for what the default behavior is, as long as there is an available parameter to allow choosing the intended new line space behavior.

@Rich-Harris
Copy link
Member Author

I'm going to close this as the thread has become a bit too chaotic to actually convert into actionable items, and because Svelte 5's whitespace handling is much more consistent and logical than Svelte 4's.

Obviously there's no silver bullet, given that browser whitespace handling takes account of the CSSOM, but I think we've landed on the least worst set of options (and cases like #189 (comment) are handled). For dealing with unwanted spaces between list items (the <ul><li>... examples), try flexbox!

If there are specific bugs or things that need further discussion, feel free to open new issues.

@nilslindemann
Copy link

nilslindemann commented Apr 2, 2024

@Rich-Harris, I can not help having the impression that you did not understand my issue. I guess a lot of people here did not, or had other problems.

So let me point it out a last time: you preserve whitespace between nodes, which is good, but you should only preserve inline whitespace between nodes. Whitespace between nodes, which also contains one or more newlines, should be completely deleted.

That, because usually we format HTML in a way that inserts newlines between (often block element) siblings, where we don't want to have whitespace in between in the output.

But your way will insert the whitespace (which is good if it is just inline whitespace!), and it will cause problems which can usually be solved with display:flex, the anti-whitespace miracle weapon, still, the resulting outputted HTML is impure.

@Rich-Harris
Copy link
Member Author

Whitespace between nodes, which also contains one or more newlines, should be completely deleted.

I understood perfectly well, I just don't agree with this statement.

There are two options here: we can make Svelte behave as much like HTML as possible, or we can make Svelte behave differently to HTML in subtle ways and force people to do horrible stuff like this:

<p>
  If this text is long enough,{' '}
  <strong>this element</strong>{' '}
  ends up on a different line
</p>

I see that a lot in React apps, and it's unforgivably ugly.

display: flex is good, and this is what it's for. Use it!

@non25
Copy link

non25 commented Apr 2, 2024

There are two options here: we can make Svelte behave as much like HTML as possible, or we can make Svelte behave differently to HTML in subtle ways and force people to do horrible stuff like this

What about giving an option though?

@nilslindemann
Copy link

@Rich-Harris In my opinion that is an unusual code formatting. I would never do that in HTML or markdown, unless forced to. But I do not read as much code as you do, maybe people indeed format their code like that a lot.

Still, I like the syntax with {' '} at the end of the line.

  • It is explicit.
  • It can be avoided by writing everything in one line.
  • People have full control over white space in the output.
  • Yet they can format the HTML nicely in the input (if they don't format it like in your code example).
  • It is more liberal, everyone can decide to have or to not have whitespace. Your way disallows people to not have whitespace (unless they format the HTML in a strange way).

You may want to help people with a more elegant syntax, but it backfires for some.

Indeed, I would appreciate an option: whitespace:react-style or however written.

@nilslindemann
Copy link

nilslindemann commented Apr 4, 2024

Another comment: It may be that these {' '} are inserted by formatters and people actually write this in a line. AFAIK e.g. the Deno formatter does that. It inserts and removes those according to the given max line length. So people do not write this by hand.

@bdmackie
Copy link

bdmackie commented Aug 1, 2024

I'm about 9 months into learning Svelte and I only realised this week that this topic is the root cause of several "strange layout" issues I've worked around over that time. It is definitely a "trap for young players", and it isn't entirely obvious to me now how to backtrack from seeing the whitespace in the browser to the offending Svelte component.

Using 'flex' works in some places but in others has side-effects. A notable one is when using styles (in my case tailwind) to position absolute items to a relative parent using styles, e.g. positioning a dropdown popup. With 'flex' enabled it simply doesn't work. It's possible I could find another workaround, but if that is just a spiral towards styling everything that is dynamic in Javascript I don't think that's the future we all want.

Perhaps there is more knowledge on how to create components that don't emit this kind of whitespace or how to troubleshoot it when it happens. Failing that, it'd be great to manage it by exception somehow (<svelte:whitespace emit="false"> or some sort of component/page directive?). No need to label it 'react' either just describe what it does canonically.

For now, my preferred hack is to put these tailwind utilities on the offending container when I don't want flex side effects: text-[0px] leading-[0px].

Update: The above hack has it's own side effects (you forget you use it and wonder why text disappears in places 🤦). Better to use whitespace-nowrap (tailwind) on containers by default and reverse that when you need to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler Changes relating to the compiler feature request
Projects
None yet
Development

No branches or pull requests