Svelte: Syntax changes

Created on 5 Apr 2018  Β·  125Comments  Β·  Source: sveltejs/svelte

Update 12 April

Most of these decisions are fairly settled at this point β€” you can see a summary here.

Original issue follows:


I've referred to this obliquely in other issues, Gitter, etc, but haven't quite got to the point of starting a proper discussion about it.

Essentially, for version 2 I'd like to move away from the Mustache-esque template syntax to something a bit lighter and more modern, which boils down to using one curly brace instead of two:

<h1 class={myClass}>Hello {name}!</h1>

The success of JSX has proved that the second curly is unnecessary. Moreover, a lot of people β€” particularly those who have been exposed to React β€” have a visceral negative reaction to double curlies, many of them assuming that it brings with it all the limitations of crusty old languages like Mustache and Handlebars, where you can't use arbitrary JavaScript in expressions.

We would also put an end to this sort of thing β€” component properties being typecast β€” at the same time. (See #657).

Quoted attributes

At present, Svelte allows you to quote attributes and properties for the sake of your syntax highlighter:

<Widget x={{y < z ? }}>this generally breaks highlighting</Widget>
<Widget x="{{y < z ? }}">this generally breaks highlighting</Widget>

I'd suggest that we keep that behaviour, so as not to force people to adopt additional tooling (which doesn't yet exist anyway). The same goes for directive arguments β€” these would be unchanged.

Control flow

It's less clear what to do about if/else/elseif, each, and await/then/catch. We could of course do this...

{#if foo}
  <p>foo!</p>
{else}
  <p>not foo!</p>
{/if}

...though part of me feels like we're just continuing to accept the premise of Handlebars, and that there's a more natural approach waiting to be discovered. Just for the sake of argument:

#if (foo) {
  <p>foo!</p>
} else if (bar) {
  <p>bar!</p>
} else {
  <p>neither foo nor bar!</p>
}

<ul>
  #each (cats as cat) {
    <li><a target='_blank' href={cat.video}>{cat.name}</a></li>
  }
</ul>

#await (promise) {
  <p>wait for it...</p>
} then (answer) {
  <p>the answer is {answer}!</p>
} catch (error) {
  <p>well that's odd</p>
}

Maybe that makes you want to barf, I don't know. But I'd be very interested to hear everyone's ideas.

Keyed each blocks

I'm in favour of replacing @name with by name, as discussed in #703 β€” it has some clear advantages.

Triples

Triples could arguably be unchanged β€” if anything, the increased distinction between {text} and {{{html}}} is a good thing. Or we could go in a totally different direction like <{html}>. Eager to hear thoughts.

Static tags

364 β€” briefly discussed, but never acted upon: the idea of adding syntax for declaring tags static, as a way of saying to the compiler 'this will never change after the initial render, don't worry about generating update code'. Would be nice if whatever choices we make preserve that possibility.

Escaping

If you needed a literal { character in your markup, you could always do {'{'}. (This is how it's done in React.) Or you could do &#123;, which is pleasingly easy to remember. Does there need to be some method of escaping beyond that?

Migrating

All this stuff should come with an simple, completely automated way to upgrade an existing template. There could be a CLI tool, and the REPL would detect old templates and show an 'upgrade' button.


Obviously we shouldn't rush into anything. But changes like these are best made earlier on in a project's lifecycle, so I'm eager to hear what people think so that we can start making some progress. Thanks!

Most helpful comment

{else}/{:else}

It's honestly a bit weird that we currently have a regular {{else}} tag for something structural. It means we can't just say, straightforwardly, that any time you have a plain tag it's a JavaScript expression.

Besides, I think there's something rather pleasing and logical about all the keywords here being vertically aligned:

artboard 1w

It does make parsing easier, which shouldn't be decisive, but is a benefit when it comes to things like (say) building a language server or porting the parser to Tree-sitter.

And in terms of ease of typing, your finger is already on the Shift key and the : key is right next to the { key where your finger already is (at least on US/UK keyboard layouts), so I'm not convinced it's burdensome, especially when you consider that it will make it possible to do things like tab-autocomplete :else, :elseif $1, :then $1 and :catch $1. It has benefits all round!

${tags}, web components and interop

This was discussed earlier, but to reiterate, ${tag} isn't practical because there is no sensible way to do control flow. There's no benefit to pretending that component templates are giant ES6 template literals β€” for example, if they were, you'd be able to use ${tags} inside your <style> and <script> elements. It just confuses the mental model.

We are creating new syntax β€” unavoidably β€” so our task is to create the most natural, logical DSL for the purpose at hand. Nothing we've talked about here has any impact on whether Svelte components are interoperable with other systems. Our goal shouldn't be to create a format that could be consumed by other compilers, but to ensure that the compiled code can continue to be used wherever. (Every so often someone will attempt to create a source format that works across frameworks. They always founder!)

html/static

Thought about this a bit more and I reckon this convention is best in terms of aesthetics and typeability:

<div class='markdown-preview'>
  {@html marked(markdown)}
</div>

(html rather than unescape because I think the concept of 'unescaping' is really a holdover from the days of string templating languages, and the intent is less clear.)

<:Window> etc

I'm persuaded that we should have a prefix for the built-in components. There's something awkward (I think) about <svelte:Window> though β€” what if we did this instead?

<svelte:head>
  <title>here we go</title>
</svelte:head>

<svelte:window on:resize='handleResize()'/>
<svelte:component {Thing} foo='bar'/>

{#if x}
  <svelte:self/>
{/if}

Something about that feels logical to me.


I feel pretty good about these changes and am ready to start implementing them. Thanks everyone for the ideas and extremely fruitful discussion β€” I realise not everyone got the outcome they were hoping for and some of you will have lingering doubts about this direction, but hopefully in time it will come to feel natural (especially once we start delivering on our long-held tooling ambitions).

All 125 comments

All Ideas presented here are very reasonable. Particularly I like Static Tags and control flow syntax changes the most.

Actually, I feel no pain with current, mustache-like, syntax. Maybe because I work with it in Ractive and worked even before Ractive.

But I always thought that if Svelte will change its syntax to something new, it will more look like ES6 Template Literals:

<h1 class="${myClass}">Hello {name}!</h1>

But in this case, we need to decide which syntax will be for blocks:

${if foo}
  <p>foo!</p>
{else}
  <p>not foo!</p>
{/if}

If there are any serious reasons to not use this standard, well, then it's completely up-to-you.

Btw, I also personally like Dust-syntax: https://github.com/linkedin/dustjs/wiki/Dust-Tutorial

I like it, single/double braces sometimes trips when switching between svelte and react.
I'm unsure about what to think of the control flow syntax, but I think I like the style closest to js the most.
using curly braces to denote blocks feels most natural. But maybe not in html style templating.

the limitations of crusty old languages like Mustache and Handlebars, where you can't use arbitrary JavaScript in expressions

Currently you can't use arbitrary JavaScript expressions everywhere you would like to. We could simplify the compiler code by having one expression parsing path instead of each directive and binding using it's own. For example, transitions require an object literal when it could be desirable to use a member, setting the options on data. There are issues to solve, such as methods being pulled from helpers in bindings but pulled from the public component API in events. However, this is a digression from the topic of this issue and should be discussed in more depth elsewhere if it has any merit. My apologies.

For the rest:

  • :+1: for keeping quoted attributes right now
  • :+1: for {#if} and :-1: for #if { which I find very hard to read/follow in HTML, esp with the other parts: } else { and }
  • :+1: for triple curlies for unescaped HTML
  • :+1: for using "by name" in keyed blocks
  • FWIW I'm not sure static tags should use single brackets (<div>[Something]</div>) because brackets are not uncommon in HTML designs. Even double brackets are used to decorate navigation. I've never done this or encouraged it, but I know of websites that do. Using CSS ::before and ::after to add [ ] could be a workaround though, so on second thought maybe that will be ok for that use-case. Still, it is more commonly used than curly braces, something to consider.

Exciting stuff! :smiley: I'm positive on these changes, and excited about decreasing the curlies.

The #if (foo) { syntax seems fine to me, but no strong preference for it versus the current syntax. I'm not currently capable of imagining something superior and new, but I'll keep my eyes open.

Is there any reason not to use backslashes to escape curlies? \{

Maybe going down the route of any escape characters at all would be confusing, and people would start expecting things like \n to work.

1) Curly: Go from two down to one throughout Svelte. Easier to understand and clear for v2 imo
2) Keyed each blocks: prefer "key name" rather than "by name". Shows purpose clearly
3) Triples: as is
4) Static tags: @TehShrike suggestion at component level seems good,
otherwise [[wontChange]] or maybe even simply enclosing in backticks {`wontChange`}?
looking forward to it!

I always thought that if Svelte will change its syntax to something new, it will more look like ES6 Template Literals:

I wondered about that. But as you mention, the control flow makes it tricky, because it's not really a template literal β€” it's a DSL. I thought perhaps it's better to have something that's explicitly different, than something a bit 'uncanny valley'.

πŸ‘ for {#if} and πŸ‘Ž for #if {

Am by no means wedded to that second idea β€” I came up with it more or less as I was typing it. Just want us to have a think about whether there is a better solution than {#if ...}, and if there isn't then that's fine too.

Is there any reason not to use backslashes to escape curlies? \{

I had the same question earlier and googled 'react escape curly braces' and landed here: https://github.com/facebook/react/issues/1545. Feels like a slippery slope.

Re static tags, I'm not suggesting that they should be part of these initial changes, just that we don't prevent ourselves from doing it in future. Static-ifying stuff at a component level could be done, but it doesn't address this sort of thing:

{{#each dynamicList as item}}
  <p>[[item.name]]</p>
{{/each}}

Tag-level and component-level aren't mutually exclusive though, we could do them independently.

Things that I miss most from Vue:

<!-- Bind expression to attribute with `:` -->
<h1 class="some-static-class">Hello!</h1>
<h1 :class="someClassExpression">Hello!</h1>

<!-- Bind event handler with `@` and pass event as first param. -->
<h1 @click="greet">Hello!</h1>

<!-- Event handler options -->
<button @click.prevent="greet">Hello!</button>
<:Window @keydown.esc="close"></:Window>

What bothers me most from Svelte:

<!-- I want to bind the value of this custom input just like I would bind to normal input -->
<input bind:value="query" /> <!-- works -->
<search-input bind:value="query" /> <!-- doesn't work :/ -->

Proposal for double binding:

<search-input ::value="query" />

For templating, I don't mind the handlebars. It's familiar for Vue and Angular users. I have never regretted keeping logic in my templates to a minimum. So I don't agree with the "visceral negative reaction" argument.

IDK about doubles vs. singles, but #if (foo) { looks horrible to me. Triples are fine as they are IMO.

@Rich-Harris I've an idea, why not use a unified scheme for all things:

{:sign[:key][:expression]}

For example:

<h1 class="{=myClass}">Hello {=name}!</h1>

Control flow

{#if foo}
  <p>foo!</p>
{:else}
  <p>not foo!</p>
{/if}

<ul>
  {#each cats as cat}
    <li><a href="{=cat.video}">{=cat.name}</a></li>
  {/each}
</ul>

{#await promise}
  <p>wait for it...</p>
{:then answer}
  <p>the answer is {answer}!</p>
{:catch error}
  <p>well that's odd</p>
{/await}

Keyed each blocks

<ul>
  {#each cats as cat, key}
    <li><a target='_blank' href="{=cat.video}">{=cat.name}</a></li>
  {/each}
</ul>

Triples

<div>{&html}</div>

Static tags

<div>{~text}</div>

Escaping
Seems, using obligatory signs parser able to ignore brackets without appropriate sign after that.

Possible signs:
{= } - escaped interpolation
{& } - unescaped interpolation
{~ } - static interpolation

{# } - start of block
{: } - sub-block
{/ } - end of block

Most likely, the signs have to be others, it's just an example. The main ideas - use single scheme with the equal parsing rules:

  1. use single brackets
  2. start sign is signaled about what will be it's parsed
  3. following expression depends on sign

As I could imagine, the unified scheme should simplify parsing. Correct me if I'm wrong.

p/s Sorry for verboseness, you said that you're very interested to hear everyone's ideas.

single curlies are fine with me. As for the blocks I'd prefer {#if ... style. Yet I like vue's v-if= attribute style a bit better. It's more concise and you don't actually need another set of closing directives.

I like the single curlies for interpolation. Using them for {#if} etc. also seems fine to me. The other #if { syntax does indeed make me barf a little for some reason. I don't have strong opinions about triple tags, those can stay at three braces probably.

For static tags, iirc Angular 1.something introduced one-time bindings, where the value inside the {{ }}s would begin with a colon. So {{:foo}} would cease updating in the document once foo had a non-undefined value. I like this a bit better than square brackets, which it seems will make escaping a bit more of a hassle. (I don't tend to use brackets or braces too much in regular old html, but I probably use square brackets more.)

As for escaping: For some reason I wasn't thinking about the &#123; possibility. I think that works well enough, and doesn't produce the additional unnecessary code that {{'{'}} does. I think just mentioning that in the docs would suffice.

I've used if and each attributes in frameworks. It simplifies the syntax, but I've really enjoyed Svelte's blocks not being element-bound. Plenty of times I've had to add a <span> tag to employ an if, but with Svelte I don't need to.

I like @PaulMaly's idea, but I would like it if the "default" sign was = to simplify. Anything that isn't an escaped interpolation would require a sign. And you could use = if you wanted to be explicit.

I just gave @PaulMaly's suggestions a proper re-read, and they are interesting. I like the succinctness but I'm also concerned about this resulting in punctuation salad. (Insert Perl joke here.) Perhaps some middle ground - which I realize is unhelpfully vague.

@jacwright @Conduitry Thanks,

I would like it if the "default" sign was = to simplify. Anything that isn't an escaped interpolation would require a sign. And you could use = if you wanted to be explicit.

Agree. I just tried to show the main idea. But, if obligatory using of signs would help with a literal { characters without any workarounds I think it reasonable price too.

I like the succinctness but I'm also concerned about this resulting in punctuation salad. (Insert Perl joke here.) Perhaps some middle ground - which I realize is unhelpfully vague.

Yep, it's just a number ideas but seems we already have some of those things like {#if ...} and {/if}. So maybe it's just some kind of unification.

I applaud the effort to simplify things for 2.0! The current syntax feels sprawling and ad hoc.

The general approach that @PaulMaly suggested looks like a good idea to me. You can remember a simple rule like "everything inside curlies is Svelte specific stuff", and then look up details as needed as you go.

The specifics are of course infinitely bikesheddable. To reduce punctuation salad, maybe common interpolation could simply be {myVar}, and special cases could be marked with readable words like {unescape myVar} and {static myVar}. It is easier to google "svelte js unescape" than "svelte js {&" or "svelte js {{{".

I think blocks could also be simplified to just use reserved words, like {if condition1} <A /> {elseif condition2} <B /> {endif} or similar. If additional punctuation is needed for syntactic disambiguation or clarity, it might be a good idea to harmonize it with directives and special components too, which are currently marked with colon. So maybe {:if condition}, {:static myVar}, etc.

On the general topic of simplifying syntax in a breaking way, I would like to recall #878 and #1069. Remove the poorly motivated special syntax for declaring dependencies of computed properties, so the <script> tag just uses standard, valid Javascript. It is an unnecessary gotcha that you can't use higher order functions or simple references in this part of the component.

+1 for new control flow #if {...

+1 for <{html}>

Oh man...

Please, please, PLEASE keep the normal quotation inline as you mention above regarding tooling: <foo bar="{baz}"> etc. It really drives me batty when our syntax actually does start to resemble something too far afield from native HTML.

Can we also bikeshed on stuff like <:Window/> tags, etc? That little colon after an opening brace doesn't parse well with many current tooling systems. I know you like it's easily identifiable difference from "normal" HTML for good easy to distinguish reasons. But why not just capitalize and call these components reserved?

<Window/>

The parser can throw an error if one uses a reserved component namespace.

I too like @PaulMaly's notation as well as the recommendation elsewhere to allow {=foo} and {foo} as the same.

Oh, also, I agree:

πŸ‘ for {#if} and πŸ‘Ž for #if {

What happens when a new framework becomes really popular and starts using double curlies?

Can we also bikeshed on stuff like <:Window/> tags, etc? That little colon after an opening brace doesn't parse well with many current tooling systems. I know you like it's easily identifiable difference from "normal" HTML for good easy to distinguish reasons. But why not just capitalize and call these components reserved?

πŸ‘+1

Btw, we already have one reserved tag: <slot>. It looks like very similar - special, reserved tag.

Would it be possible to make the templating engine pluggable, so that the community could write e.g. a svelte-jsx or svelte-lithtml adapter?

Would it be possible to make the templating engine pluggable, so that the community could write e.g. a svelte-jsx or svelte-lithtml adapter?

If I remember right too many things locked on the internal handwritten parser. For real good approach, we can use something like Flex/Bison but I don't know about JS in this case.

Since we already have special "HTML" tags like <:Window>, would it be reasonable to make all control structures into special tags?

<:if myVar>
  <span>Something</span>
<:else />
  <span>Something else</span>
</:if>
<ul>
  <:each myArray as el>
    <li>{el}</li>
  </:each>
</ul>

That makes a clear distinction between things that control the DOM structure (<:thing>) and things that output text ({thing}).

It also has the benefit of being quite readable in editors:
screen shot 2018-04-06 at 9 06 16 am

Oh my, I wasn't expecting so much feedback! Thanks everyone, this is fantastic.

@hperrin's idea is pretty cool. You get auto-completion as a nice bonus! The self-closing <:else /> is a bit awkward though, and the same would be true for <:await...> β€” I wonder if it should be like this instead:

<:if myArray.length>
  <ul>
    <:each myArray as el, i>
      <li>{el}</li>
    </:each>
  </ul>

  <:else>
    Nothing in the array
  </:else>
</:if>

<:await promise>
  <p>loading...</p>

  <:then value>
    <p>the value is {value}</p>
  </:then>

  <:catch error>
    <p>oops! {error.message}</p>
  </:catch>
</:await>

Maybe it's too weird having else (and elseif) inside if, and maybe it would interact badly with certain tooling (@arxpoetica can you be more specific on that point?). Curious to hear what people think.

@arxpoetica

It really drives me batty when our syntax actually does start to resemble something too far afield from native HTML

I don't totally follow this point β€” <input type=range min=0 max=100 > is valid HTML β€” the quotes are entirely optional for attributes without spaces as of HTML5 πŸ˜€

@thgh the Svelte equivalent for those Vue idioms is this β€”Β I'm not sure I understand what the drawbacks are? (These are more flexible and explicit IMHO, and barely any extra characters.)

<h1 class="some-static-class">Hello!</h1>
<h1 class={{someClassExpression}}>Hello!</h1>
<h1 on:click="greet(event)">Hello!</h1>

For the event modifier stuff see #1088. Bindings on custom elements is something we should support, I don't think we currently have an issue for it though.

@PaulMaly that's a really strong proposal, thanks. Agree with the other comments the {= is probably unnecessary and could just be {. @trbrc makes a great point about searchability.

@opus131

Would it be possible to make the templating engine pluggable, so that the community could write e.g. a svelte-jsx or svelte-lithtml adapter?

In theory yes. The compiler really only needs the source string and an AST. If we properly formalised and documented the Svelte AST format, then we could allow anyone to build their own parser. I think the costs of doing so are more human than technical thoughΒ β€” having a single canonical template language is better from the point of view of documentation, tutorials, Stack Overflow, shareable components, etc.


So, consolidating everyone's input so far, my read is that the current front-runner is something like this...

  • {expression} β€” replaces {{expression}}
  • {#if expression} β€” replaces {{#if expression}}
  • {:else} β€” replaces {{else}}
  • {/if} β€” replaces {{/if}}

...with the following possible additions:

  • {static expression} (though this doesn't allow static if/each/await expressions)
  • {unescape expression} β€” replaces {{{expression}}}. Or maybe {html expression}?

But a last minute challenger has entered the race:

<:if foo>
  <p>foo!</p>
</:if>

Regarding static tags, we could use another special tag:

<:Static>
  Hello, {user.name}. Even if you update your name, I'll still call you by the old one!
</:Static>

Also, -1 for <{html}>. (It will definitely confuse editors.)
+1 for keeping {{{html}}}

Regarding @hperrin's suggestion, the simple case works for HTML parsing in browsers. Will more complex expressions hurt that at all?

<:if myHelper() !== some.value && foo.bar.length>
  Foo is true!
<:else />
  Foo is false. :(
</:if>

I like it. But I'm leaning to {#if}, possibly because it stands apart more, possibly because I'm more used to that syntax in Svelte.

I'm personally not a huge fan of <:if..., for two reasons:

  1. I forsee this highlighting _very_ poorly in some editors.
  2. It doesn't stand out from the rest of the template; it's a conditional, not an element.

I completely agree with @RyanZim. Also seems @arxpoetica suggested to replace this <:Tag /> syntax with just regular reserved tags like <slot> and it's also a good idea. So, I suppose that main reason for this variant (Since we already have special "HTML" tags) is almost out of the race.

Personally, I've one more reason not to vote for this variant - I remember the time when I used PHP in my work. PHP was designed to be injected in HTML conveniently, but first thing what we did before starting a project - choosing template engine. Because of this:

<ul>
<?php if(!empty($todo)):?>
<?php foreach ($todo as $item):?>
  <li>
      <input checked="<?=$item['done']?>">
      <?=$item['body']?>
  </li>
<?php endforeach;?>
<?php else:?>
   <li>No todos</li>
<?php endif;?>
</ul>

Too many angle brackets, you know. This one looks much better (Smarty Template Engine):

<ul>
{foreach $todo as $item}
  <li>
      <input checked="{$item.done}">
      {$item.body}
  </li>
{foreachelse}
  <li>No todos</li>
{/foreach}
</ul>

It looks like @RyanZim's first point is valid in Sublime Text.
screen shot 2018-04-06 at 11 52 16 am

VS Code and Atom look fine.
screen shot 2018-04-06 at 11 52 06 am
screen shot 2018-04-06 at 11 51 51 am

One big bonus in all of them, though, is the matching tag highlighting.

I translated a big component of mine, and after seeing how botched it looks in Sublime, I'm taking back my own vote for <:if>. 😭 It's too bad too, cause it highlights really well in VS Code. Better than {#if}.

Regarding renaming the special tags from <:Name> to <Name>, I think that's a really bad idea. It invites name collisions in the future. If beginning the tag name with a colon breaks a lot of tools, we can pretend it's a namespace, and choose something simple, like "s":

<s:Window ... />

@hperrin We already have reserved <slot> tag which basically comes from Web Components standard current revision. So, there won't be a problem to have a few additional reserved tags.

Would anybody like to replace each (cats as cat) with for (cat of cats) to be more EcmaScript-like. May be not replace but add an alternative.

I'm against <:if> style tags due to how ungainly they are to type.

Finger DX is important.

So, looks like <:if ...> is out. It was a nice idea!

Seems folks are generally on board with {expression}, {#if expression}, {:else} and so on. Think we're probably at the point where we can exclude that from further bikeshedding.

I realised that {static expression} and {unescape expression} or {html expression} aren't as practical as we first thought, because of ambiguities about how to parse them:

{html (expression)} <!-- could be CallExpression or prefixed ParenthesizedExpression -->
{html + whatever} <!-- could be BinaryExpression or prefixed UnaryExpression -->

So we either need to choose sigils for those cases, or prefix the keywords, e.g.

{=html expression}

I think prefixing is better, but have no strong opinion about which special character would make most sense (except a mild aesthetic preference for characters with vertical symmetry, and a suggestion that we avoid < and & because they have special significance in HTML and will cause highlighting weirdness).

I agree with @hperrin about names for special components β€” I don't think it's wise to have <Window> and <Component> etc. <slot> is different precisely because it's an element with special meaning in HTML, and Svelte slots behave like 'real' ones do.

@constgen Have wondered about that. The reason I think it's probably best not to is that we can currently use indexes (each cats as cat, i) and for (cat, i of cats) would be odd. Also, there's no good place to put by name or key name. I'm generally against having multiple ways of doing the same thing, since it creates anxiety about which is the 'right' one and what the differences are between them.

We're almost there! Think we basically just need to figure out the HTML/static tags thing.

Whew I am so relieved <:if ...> didn't land. πŸ‘ Those little colons right after the angle brackets really mess with my current tooling.

@Rich-Harris

It really drives me batty when our syntax actually does start to resemble something too far afield from native HTML

I don't totally follow this point β€”

Yes, but curly braces aren't considered serializable. So keeping the quotes allows for tooling that tries to serialize.

I agree with @hperrin about names for special components β€” I don't think it's wise to have and etc. is different precisely because it's an element with special meaning in HTML, and Svelte slots behave like 'real' ones do.

I definitely understand the point about it being intentional to separate it from regular components and HTML. So let's just stick on the discussion similar to <:if ...> about the colons in <:Window/> and <:Head/> messing with environment tooling.

I like @hperrin's recommendation to simply prefix it:

<s:Window ... />

That immediately solves the tooling problem. I could get behind that. It also makes it feel even a tad more intentional, i.e., that s: means something. It's a namespace. This actually goes well with the whole component marketplace idea, not to veer the discussion too far afield, but we've talked about namespacing before, and this fits with that. Hell, it could even be <svelte:Window/> but I like the shorter <s:Window/> more.

For that matter, maybe <s:*> ought to be the official namespace for all Svelte marketplace components.

Please can we do something other than <:Window/>? Pretty please???

image

{#if expression}, {:else}

Multiple prefixes # : = will confuse new users. In my opinion We should use the same prefix everywhere or If possible completely avoid them
{if condition}... {else}...{/if} etc.

@ansarizafar I believe that developers able to remember a few prefixes. The unified schema would simplify parsing process.

Possible prefixes, I guess:
{~foo}
{?foo}
{=foo}
{%foo}
{^foo}
{*foo}
{@foo}

{πŸ”foo}

If we did want to avoid prefixes all together, we could emulate one advantage of the <:if> syntax by clearly separating control structures from output. Maybe something like:

{if textIsSafe}
  <span>{{{text}}}</span>
{else}
  <span>{{text}}</span>
{/if}

So single curly brace means a control structure, double curly brace means escaped output, and triple curly brace means unescaped output.

So, consolidating everyone's input so far ... 
{expression} β€” replaces {{expression}}
{#if expression} β€” replaces {{#if expression}}
{:else} β€” replaces {{else}}
{/if} β€” replaces {{/if}}

...with the following possible additions:
{static expression} (though this doesn't allow static if/each/await expressions)
{unescape expression} β€” replaces {{{expression}}}. Or maybe {html expression}?

{:else} β€” replaces {{else}} personally not keen on {:else}/{:elseif} and can't see any reason why we need to change what we have already i.e. {else}/{elseif}. Plus extra awkard typing + not a good look imo

Now that we are going to one curly brace, we have a space we can use, why not:
{{static expression}} 2 braces
{{{unescape expression}}} 3 braces, stay as is + it is significant to do this, so it is good to stand out
On the other hand, maybe we should move away from 2 braces completely, can foresee problems in people migrating and accidentally making things static.....?

if we were to go down the prefix route then

Maybe it's too weird having else (and elseif) inside if

This actually looks like a good idea to me (regardless of <if ...> vs {if ...}). There is something awkward about the Handlebarsian syntax for if/else blocks:

{{#if user.loggedIn}}
    <a href='/logout'>log out</a>
{{else}}
    <a href='/login'>log in</a>
{{/if}}

The pair of {{if ...}} {{/if}} blocks are similar to HTML, but what is going on with that {{else}} dangling by itself in the middle? HTML either uses pairs of tags enclosing some content, or self-closing tags when there is no additional content. The sandwhiched else breaks those rules. Having it as its own nested block inside the if fixes it.

Another fix would be more like @Rich-Harris's first proposal in the thread, which avoids the closing /if altogether.

I realised that {static expression} and {unescape expression} or {html expression} aren't as practical as we first thought, because of ambiguities about how to parse them:

{html (expression)} <!-- could be CallExpression or prefixed ParenthesizedExpression -->
{html + whatever} <!-- could be BinaryExpression or prefixed UnaryExpression -->

Good point! OTOH, we might treat them as reserved keywords and simply not allow data to use those names. At the moment, the compiler will not allow expressions where the data is called "class", "default", "for", etc, so there are already limits on what you data can be called.

If there has to be a prefix, I would strongly vote for ${foo}. Don't invent new prefixes πŸ˜ƒ

I'm not sure I understand what the drawbacks are? (These are more flexible and explicit IMHO, and barely any extra characters.)
<h1 class={{someClassExpression}}>Hello!</h1>

I like that handlebars can contain expressions, it makes total sense. But the fact that handlebars can output objects feels awkward, e.g. <SomeComponent data="{{someObject}}" />. I thought HTML only allows strings in attribute values.

@thgh, seems it’ll look strange with Store properties: ${$foo}

ok, looks like you seriously decided to change syntax... I have only one wish: the finish of this action should be syntax plugins for VSCode/Atom/Sublime.
And of course I can help with VS Code but it's should be part of the Svelte2 milestone.

Just another opinion in the fray:

Personally, I feel one of the strongest arguments svelte has is made by the original post by @Rich-Harris , discussing svelte apps as Web Components. The further it strays from it's initial ply of interopability, the more of an argument it is for someone to use a more fleshed out framework.

Which leads me to believe the ideal situation would be Web Components with standard JS tokens in the raw. That is, without any mustache-like tokens nor svelte-specific ones.

<SubComponent />

if (foo) {
  <SubComponent />
}
else {
  <SubComponent />
}

<SubComponent />

But, I don't know of the feasibility of it, so my vote would go towards ${if foo} style as an alternative.

TL;DR: the less Domain Specific Language aspects of svelte, the better.

Ideal situation would be Web Components with standard JS tokens in the raw. That is, without any mustache-like tokens nor svelte-specific ones.

I completely agree with @RoryDuncan

All the syntax changes look very sane, but not a fan of the propsal for if...else. Mustache style is worth avoiding, sure, but for all its faults, its if...else style is very grokkable.

Definitely not a fan of if/else tags, as it begins to look like Java Struts / Stripes / Server Faces / JSP whatever else we used to use a million years ago.

{:else} β€” replaces {{else}} personally not keen on {:else}/{:elseif} and can't see any reason why we need to change what we have already i.e. {else}/{elseif}. Plus extra awkard typing + not a good look imo

+1

{else}/{:else}

It's honestly a bit weird that we currently have a regular {{else}} tag for something structural. It means we can't just say, straightforwardly, that any time you have a plain tag it's a JavaScript expression.

Besides, I think there's something rather pleasing and logical about all the keywords here being vertically aligned:

artboard 1w

It does make parsing easier, which shouldn't be decisive, but is a benefit when it comes to things like (say) building a language server or porting the parser to Tree-sitter.

And in terms of ease of typing, your finger is already on the Shift key and the : key is right next to the { key where your finger already is (at least on US/UK keyboard layouts), so I'm not convinced it's burdensome, especially when you consider that it will make it possible to do things like tab-autocomplete :else, :elseif $1, :then $1 and :catch $1. It has benefits all round!

${tags}, web components and interop

This was discussed earlier, but to reiterate, ${tag} isn't practical because there is no sensible way to do control flow. There's no benefit to pretending that component templates are giant ES6 template literals β€” for example, if they were, you'd be able to use ${tags} inside your <style> and <script> elements. It just confuses the mental model.

We are creating new syntax β€” unavoidably β€” so our task is to create the most natural, logical DSL for the purpose at hand. Nothing we've talked about here has any impact on whether Svelte components are interoperable with other systems. Our goal shouldn't be to create a format that could be consumed by other compilers, but to ensure that the compiled code can continue to be used wherever. (Every so often someone will attempt to create a source format that works across frameworks. They always founder!)

html/static

Thought about this a bit more and I reckon this convention is best in terms of aesthetics and typeability:

<div class='markdown-preview'>
  {@html marked(markdown)}
</div>

(html rather than unescape because I think the concept of 'unescaping' is really a holdover from the days of string templating languages, and the intent is less clear.)

<:Window> etc

I'm persuaded that we should have a prefix for the built-in components. There's something awkward (I think) about <svelte:Window> though β€” what if we did this instead?

<svelte:head>
  <title>here we go</title>
</svelte:head>

<svelte:window on:resize='handleResize()'/>
<svelte:component {Thing} foo='bar'/>

{#if x}
  <svelte:self/>
{/if}

Something about that feels logical to me.


I feel pretty good about these changes and am ready to start implementing them. Thanks everyone for the ideas and extremely fruitful discussion β€” I realise not everyone got the outcome they were hoping for and some of you will have lingering doubts about this direction, but hopefully in time it will come to feel natural (especially once we start delivering on our long-held tooling ambitions).

Re. :else
Can understand the symmetry, but it'll be the only place it is used in control structures.

With the massive significance of ":" in bindings I think it's a bad move, can we not choose another character in that case?

Where are we with by name vs key name for keyed updates @Rich-harris? You mentioned both in your earlier summary but omitted it in your last update

Agree about the logical point re.

As long as we're breaking backwards compatibility, I wish we took another look at the shorthands for properties and bindings.

I don't think they're very intuitive:

<tag bind:property='property'/> shorthands to <tag bind:property/>
<tag property='{property}'/> shorthands to <tag :property/>

Could we instead have this?

<tag bind:property='property'/> shorthands to <tag bind:property/> and possibly <tag :property/>
<tag property='{property}'/> shorthands to <tag {property}/>

Granted, this would probably require <svelte:component> to be changed too. Would this be too alien?

<svelte:component={Thing} foo='bar'/>

Could we instead have this?

+1

Also, I like Vue's shorthands.

About built-in components, for me still not so clear why we can't just use reserved tags? Everyone does it. For example, Vue has many different pre-defined tags, like: component, keep-alive, slot, all list.

Regarding dynamic components, for me this variant:

<svelte:component {Thing} foo="bar" />

is less intuitive and looks petty ugly than:

<component bind:is="Thing" foo="bar" />

And also it would be great if we'll be able to register dynamic components just like regular components, inside of components property instead of data.

I belive it won't be a big problem if we'll have a limited list of reserved tags: slot, component, window, head, self

@PaulMaly definitely agree that once you start typing @click or @mousedown shorthands it:

  1. Feels very good, succinct and, most importantly, clearly differentiates between prop bindings
  2. When I first came across the shorthands, my response was: this makes complete sense & is v.elegant
  3. Terse is good (imo at least)

Unless you've used these before then it's appeal might be missed. Please just try and type the @ and : (with no-prefix) versions and see how it feels. So if you see a : it immediately indicates significance

Quite a number of Svelties seem to have Ractive backgrounds (not meant to be a criticism for a second, just alerts about experience/mindset/familiarity). Let's not reinvent a wonky wheel and also not be too proud to incorporate good ideas from others pl - if possible.

Your last example should surely have been:

<component :is="Thing" foo="bar" />  

:smile:

Lastly, it will also greatly help a lot of people who are familar with this to come to Svelte

ooh, big :+1: to {@html html} - I like that better than triple-curlies.

+1 for {@html foo}
+1 for {:else} or {@else} or {#else} or {🀷else}
+1 for <svelte:component ..., <svelte:window ..., etc.
+1 for <svelte:component bind:is="Thing" or <svelte:component :is="Thing"

Has anyone weighed in on:

<svelte:static>
  <span>{someVar} is just the way it is. It'll never change.</span>
</svelte:static>

It supports static if blocks, static each blocks, and you could make your whole component static, even.

@Rich-Harris

In theory yes. The compiler really only needs the source string and an AST. If we properly formalised and documented the Svelte AST format, then we could allow anyone to build their own parser. I think the costs of doing so are more human than technical though β€” having a single canonical template language is better from the point of view of documentation, tutorials, Stack Overflow, shareable components, etc.

Would it be possible to make the template parser available for other libraries and stuff? I really like the syntax so far and I'm pretty sure I will also like what you have planned vor v2 now.

I'm currently building a small layer with some syntactic sugar on top of custom elements. I have it working with handlebars at the moment but I think the svelte parser would be much more lightweight and also much more natural with real javascript expressions and stuff.

Why we need all these special characters like # : / ? I think more readable will be:

{if foo}
  <p>foo!</p>
{else}
 <p>not foo!</p>
{endif}

About {else} - anyway JS expression can't starts with "else" word.

@stalkerg I think Rich outlined it pretty well here:

image

Personally, I'm fine either way, but it is a good point that a character indicates it's not just interpolation. I.e., what happens if you have a variable named else? How do you interpolate that? Rich also makes the point that it makes parsing easier.

@stalkerg it’s very similar to PHP short syntax and not so bad, actually. But I don’t think it’s more readable:

{each foo as bar}
...
{endeach}

{await foo}
...
{endawait}

Also in this case interpolation would be:

{=foo}

to prevent misunderstandings.

Just for comparison (todo list):

PHP-like variant:

{await todos}
    <p>Loading...</p>
{then todos}
    <ul>
    {each todos as todo}
            <li class="{=todo.done && 'done'}">
            <input bind:checked="todo.done" type="checkbox">
            {=todo.body}
            </li>
        {else}
            <li>No todos</li>
    {endeach}
    </ul>
{catch err}
    <p>{=err}</p>
{endawait}

Current Rich-approved variant:

{#await todos}
    <p>Loading...</p>
{:then todos}
    <ul>
    {#each todos as todo}
            <li class="{todo.done && 'done'}">
            <input bind:checked="todo.done" type="checkbox">
            {todo.body}
            </li>
        {:else}
             <li>No todos</li>
    {/each}
        </ul>
{:catch err}
    <p>{err}</p>
{/await}

Kinda feels like : is being used as a continuation character, when it is generally seen as a namespace character.

Perhaps it's ugly but:

{#if condition}
...
{&else}
...
{/if}

or

{#if condition}
...
{~else}
...
{/if}

Want to add some new options:

  1. Special reserved components: <$Window>, <$Head>
  2. Escaped value {value}
  3. Unescaped value {{value}}

+1 for shorthand <tag {property} />.

Inline shorthand brackets are not serializable by some parsers.

@eddyloewen You can use svelte.parse. It isn't really documented, and we don't really consider it part of the API (though I suppose we probably should) so the AST format could change (and likely will for v2), but it's there!

@antony

Re {:else} versus {&else} versus {~else} β€” I don't think we should worry too much about what meanings a given character might have in other contexts; there are other considerations. & messes up syntax highlighters, so that's a non-starter...

screen shot 2018-04-10 at 10 03 45 pm

...and ~ is just plain awkward to type on a lot of keyboards. I think : is fine.

@tomcon

Where are we with by name vs key name for keyed updates

I think you're right; in #1330 I'm going with key.

@mrkishi

I would like to retire :property β€” I've seen it cause a lot of confusion. At first I wasn't too keen on {property} but it's grown on me, and it seems to be a popular proposal. As for dynamic components, I don't think we can get away with <svelte:component={Thing}> but the current syntax is deeply weird anyway, so it probably needs to change.

What about this?

<svelte:component this={Thing}/>

I feel okay about reserving this β€” moreso than is, certainly β€” and it reads more naturally when you say it out loud ('this equals Thing' as opposed to 'is equals Thing'). And in inline event handlers, this refers to the component, so it's completely logical.

@PaulMaly

Shorthands is something we could possibly revisit once v2 is out of the door, since it wouldn't be a breaking change to add them later. I'm definitely not convinced that <window>, <head> etc are a good idea β€” it might be a short list of built-in elements, but it still assumes people reading components have certain fairly esoteric knowledge. And short lists can sometimes become medium-sized lists.

@hperrin <svelte:static> could work β€” I don't think we should worry about it for v2.0.0 though.

@constgen <$Foo> isn't any more valid than <:Foo> β€” it suffers from the same highlighting problem.


I'm slowly implementing this stuff over on #1330, and will continue to incorporate feedback, though I feel like most of the questions are probably settled at this point. Thanks all

@Rich-Harris Re: dynamic components, I _do_ prefer this={Thing} over is. It's just a shame we'd use a regular prop for it. It _feels_ like there should be an elegant solution somewhere... I just don't know what. πŸ˜›

Let me just throw another weird syntax in case it sparks any ideas for anyone:

<svelte:{Thing} this='regular' is='props'/>

Responding to https://gitter.im/sveltejs/svelte?at=5acd7015df3e0fb547c46901

you said 'Inline shorthand brackets are not serializable by some parsers', can you elaborate?

I keep making a stand by this idea that we all can (and should) make everyone's lives easier/simpler if we adhere strictly to normalized HTML syntax highlighting and serializing rules for any specialty Svelte syntax.

So, for example, HTML parsers accept : and @ in attribute names, but not { or }.

So doing something like <tag {property} /> won't serialize in some browsers (not important, since Svelte precompiles it for browsers) but (much more importantly) in some html text editors it may highlight incorrectly or even choke.

Nor will:

<svelte:{Thing} />

Nor will:

<svelte:component this={Thing}/>

But this does work:

<svelte:component this="{Thing}"/>

I don't think we should bank solely on "oh, we can just write Atom or Sublime or VS Code syntax highlighters." I think we should try and stay as closely as we can to something that would actually be serializable in a browser, even though Svelte does compile it down to perfect serialization.

For the record, I can cede the point if you think I'm being too hardline about it. I would just need to know that I need to cede it.

image

If we're trying to conform to parsers, I'd rather have a completely new directive than shorthanding prop='{prop}' to :prop.

<tag prop='{prop}'/> means <tag set:prop='{prop}'/> becomes <tag set:prop/>
<tag bind:prop='prop'/> becomes <tag bind:prop/>

Given that directives are formatted directiveName:argument='value', the problem is then having directives that do not take an argument name -- just a value:

<svelte:component this:='{Thing}'/> makes logical sense; is quite ugly.

Maybe we could use the current shorthand for _that_ instead? directiveName:unusedName='value' then becomes :directiveName='value':

<svelte:component :this='{Thing}'/> or <svelte:component :is='{Thing}'/>

@arxpoetica

I think Rich outlined it pretty well here:

Yep, but my visual parser in brain still see special characters before, and it's annoying.

Personally, I'm fine either way, but it is a good point that a character indicates it's not just interpolation. I.e., what happens if you have a variable named else? How do you interpolate that? Rich also makes the point that it makes parsing easier.

I think it's common practice to have special forbidden words in a language. Also, I think you should kill anybody who named variable as "else".

@PaulMaly

it’s very similar to PHP short syntax and not so bad, actually. But I don’t think it’s more readable:

I thought more about Mako Template but anyway this approach will much cleaner. If we can reduce visual trash from the code we should do it.

@arxpoetica

I think we should try and stay as closely as we can to something that would actually be serializable in a browser, even though Svelte does compile it down to perfect serialization.

Why? Do you have plans to open Svelte components in a browser directly?

Taking into account @arxpoetica points and fleshing out my previous comment, I propose we come up with a unified behavior for directives. This is my take on it without using {}@ in attribute names, since those are not accepted by some parsers (including Chrome and VSCode).

  • Directives have a name, an identifier argument and a javascript expression value:
<tag name:argument='value'>
  • When a directive value is omitted, it's assumed to be identical to argument (since it's an identifier, it's a valid js expression):
<tag name:argument> means <tag name:argument='argument'>
  • Some directives might still ignore the value:
<tag ref:refName> really means <tag ref:refName='refName'>, but `ref` doesn't use it
  • Other may not need argument, so it can be omitted:
<tag name:unused='expression'>
<tag name:='expression'>

Building upon that...

  • We have one-way and two-way binding directives:
<tag set:prop='expression'>, shorthand <tag set:prop>
<tag bind:prop='expression'>, shorthand <tag bind:prop>
  • Attributes with {expressions} in them are just shorthand to one-way binding directives:
<tag attr='{value}'> is the same as <tag set:attr='value'>
<tag attr='compound {value}'> is the same as <tag set:attr='`compound ${value}`'>
  • In order to remove {}, dynamic components have an is directive that takes no arguments, just an expression:
<svelte:component is:Thing> with shorthand rules expands to <svelte:component is:Thing='Thing'>
<svelte:component is:='signedIn ? UserPanel : GuestPanel'>
  • Likewise, {...spread} properties become a directive with an expression and no argument:
<tag spread:reference> with shorthand rules expands to <tag spread:reference='reference'>
<tag spread:='getObject(withExpression)'>
  • Directives that take function calls should have a function identifier variant so shorthand syntax is consistent:
<tag on:click> means <tag on:click='click'>, which `on` accepts
<script>
    export {
        methods: {
            click(event) {}
        }
    }
</script>

What do you think?

Prefix:
How about {#html foo} {#if foo} {#else} {#then} {#catch} ... One prefix to rule them all!

Component:
The standard states that custom elements should contain a dash -, so I would feel safe to use component as a predefined component. this refers to the current context or an instance of the component, pretty sure that will cause confusion. Isn't the react crowd allergic to this?

<component is="{signedIn ? 'UserPanel' : 'GuestPanel'}" />

HTML syntax:

I keep making a stand by this idea that we all can (and should) make everyone's lives easier/simpler if we adhere strictly to normalized HTML syntax highlighting and serializing rules for any specialty Svelte syntax.

@mrkishi There is an existing syntax out there that adheres to HTML in an elegant way:

Generally:
<tag directive:attribute="value">

Which results in
<input bind:value="oneWay"> (shorthand <input :value="oneWay">)
<input sync:value="twoWay">
<button on:click="handler()"> (shorthand <button @click="handler">)
<component :is="signedIn ? 'UserPanel' : 'GuestPanel'">
<tag ref="elem">

I feel like we got slightly derailed by the parseability concern. It's not a requirement, or even really a nice-to-have, for Svelte components to be valid HTML, because they'll never be parsed as such. They only really need to be highlightable as HTML. I've tried in Sublime, Code, Atom, Chrome devtools, the Svelte REPL, this GitHub comment box, and I haven't yet found any situation where this highlights awkwardly:

<div {foo}></div>

I fully agree that it should be possible to write Svelte components without any editor plugins, but I don't think we should abandon a good proposal for an optional shorthand based on a hypothetical. If it's not hypothetical β€” if there are specific environments where the above doesn't work β€” please let us know!

As long as we don't have the valid HTML constraint, I think the existing proposals are probably still good, with some possible bikeshedding still over <svelte:component this={Thing}> (though I personally still like it).

@stalkerg Afraid I'm not convinced that {endif} is more readable than {/if}. If I'm scanning down a page, {/if} is much easier to spot. The fact that it's less pretty is kind of the point β€” it's easier for your brain to discern structure at a glance.

@thgh are you saying it should be {#if foo}...{#else}...{#if} or {#if foo}...{#else}...{/if}? If the first, I think that would be rather confusing, if the second then the lack of symmetry (normally, # opens a block, / closes it) is unfortunate. I think the existing proposal is probably cleaner. The argument against <component> isn't that it isn't 'safe', it's that it's messy β€” it's no good making people learn and memorise a list of built-in elements before they can read and understand a component. The svelte: prefix solves that problem, and makes it possible to add new built-ins (such as <svelte:static>, mentioned above) with much less difficulty and risk.

Please, whatever you do, don't use endif. It's the second-clumsiest way to close an if statement IMO (the clumsiest being Bash's fi). It's impossible to spot when scanning code, and is unnecessarily long (5 chars vs. 3 for /if).

I like that non-HTML tags are distinguishable from regular tags but agree that the colon tags such as <:Window> are awkward. I like <svelte:window> and <svelte:component> but they feel more like regular HTML tags. Feel free to say no, but I think we should capitalize those for consistency <svelte:Component and <svelte:Window>.

And since HTML Components use is for defining what an element is, I really like using it for dynamic components.

<svelte:Component is={Thing} prop={stuff}/>

<svelte:Window on:click="doThing()"/>

And now that I'm looking at that on:click I wonder if directives should allow curlies as an alternative to quotes.

<svelte:Window on:click={doThing()} />

But that might just be because I'm working a lot in React for the day-job.

I think <svelte:window> makes more sense than <svelte:Window>. Technically they're neither components nor elements, but they're much closer to being elements, in that they expose 'native' functionality that's otherwise inaccessible to the user β€” you couldn't recreate the functionality of <svelte:self> any more than you could recreate the functionality of <video>. I also think it's much nicer aesthetically, and is easier to type.

And since HTML Components use is for defining what an element is

I tend to think this is a reason not to do it β€” if you already know about is=, then you're likely to have incorrect expectations about how it should behave (e.g. that it's supposed to be a string rather than a component constructor). Better to avoid the uncanny valley!

I wonder if directives should allow curlies as an alternative to quotes

Elsewhere (and in React), anything inside curlies is an expression that gets evaluated reactively β€” on other words, the click handler would be the result of calling doThing, rather than doThing itself, for which you'd need to do either of these, depending on whether you had arguments other than event:

<svelte:window on:click={doThing} />
<svelte:window on:click={e => doThing(e, foo, bar)} />

You could make a case for that, but it means doThing has to be a property of your data (not methods), and you'd have to jump through some hoops to preserve this. The current approach is a bit of a leap if you have the React mental model, but I believe the ergonomics are far superior.

ooh, I'm surprisingly attracted to

<svelte:window on:click={e => doThing(e, foo, bar)} />

...the magical "event" word in that context has always kind of weirded me out.

Your point about making people have to think about data vs methods and this is good though, probably not worth messing with.

I barfed at the #if syntax at first too, but after a coffee with @neoel he showed me how it highlights, and by default you get bracket matching for free :)
So in this light I did what @hperrin did, I translated some ugly template to the new styles, and I really like the #if after all, here are some screenshots.
Current:
svelte-current-syntax
Syntax 1:
svelte-syntax1
Syntax 2:
svelte-syntax2

I really like syntax 2 (#if) more than syntax 1, it looks way cleaner, and the difference between #each and #if blocks is more clear to me.

The bracket matching is nice, and it's definitely a little lighter on the page. Unfortunately I think it's just a little too controversial β€” if a lot of people instinctively have a negative reaction to it (and a lot of people did!) then it's probably a sign that we shouldn't use it, particularly from the point of view of being accessible to newcomers.

Seeing it in action there @bwbroersma it is very readable and likeable. Consider me surprised too.

I guess I'll change my 'barf' vote to a 'mildly unsettled' vote. I can't tell how much of this is just that it's novel vs. that I actually think it's bad.

i think its common also if user coming from ASP.NET as like razor syntax
but instead of using # razor using @

@Rich-Harris

I feel like we got slightly derailed by the parseability concern...

You know, upon further investigation, you're right. I'll cede the floor. ;) If specific examples come up (as you say), I'll make sure to point them out.

Here's one. For some reason, Pug/Jade isn't playing fair with:

<svelte:component this={Thing}>

But as long as I can always use quotes:

<svelte:component this="{Thing}">

Everything's good.

Update: I love that this ticket is becoming one of the longest ones on Svelte to date. πŸ˜‚ :shipit:

@antonheryanto I came form ASP.NET but I never like razor, I like more on dotlquid even I like more on old ASP.NET syntax(<% ** %>) but now, I am not sure where is the future? https://github.com/torhovland/blazor-redux
Anyway I really don't think syntax is important for v2 it's already good for my work, I hope we need more focus on https://github.com/sveltejs/svelte/issues/779

@Rich-Harris please take little time at https://shopify.github.io/liquid/ before you make final decision, I really like this template syntax, most template work for either server or client but IMO, this covers both.
And looks like it's coming from handlebar

@Kiho sorry, don't like that at all. It's basically JSP / EJS / any other full-blown templating language.

What we're really talking about here is the minimum workable set of constructs which allow us to almost have logic-less templates. Remember, the logic should live within your <script> tags, and only simple rendering concerns should be present in your html.

@Kiho Actually, I also don't see any reasons to use that template syntax. Let's compare.

Liquid:

{% await todos %}
    <p>Loading...</p>
{% then todos %}
    <ul>
        {% for todo in todos %}
            <li class="{{todo.done && 'done'}}">
            <input bind:checked="todo.done" type="checkbox">
            {{todo.body}}
            </li>
        {% else %}
             <li>No todos</li>
    {% endfor %}
        </ul>
{% catch err %}
    <p>{err}</p>
{% endawait %}

Current Rich-approved variant:

{#await todos}
    <p>Loading...</p>
{:then todos}
    <ul>
    {#each todos as todo}
            <li class="{todo.done && 'done'}">
            <input bind:checked="todo.done" type="checkbox">
            {todo.body}
            </li>
        {:else}
             <li>No todos</li>
    {/each}
        </ul>
{:catch err}
    <p>{err}</p>
{/await}

@Rich-Harris

(html rather than unescape because I think the concept of 'unescaping' is really a holdover from the days of string templating languages, and the intent is less clear.)

Just an idea: {@raw marked(markdown) }. A little bit shorter and not referenced to html-only. Or maybe even:

{#raw}
<p>Hello world</p>
{/raw}

Thinking of declarative if and for, the look not so bad:

Loop

<ul>
  <for each={items} as={item} index={i}>
    <li>Item {item.name} number {i}</li>
  </for>
</ul>

Condition

<if {items.length}>
  {items.length}
</if>

<if {items.length}>
  {items.length}
  <else>
  Empty
</if>

<if {condition}>
  this is true
  <elseif {anotherCondition || somethingElse}>
  not quite true
  <else>
  this is false
</if>

<switch {state}>
  <case when='loading' break>State: Loading</case>
  <case when={LOADED} break>State: Loaded</case>
  <default>State: Default</default>
</switch>

<else> and <elseif> are indented because this is how code editors are going to format them.

Async

<async await={whenReady}>
  <then result>Done: {result}</then>
  <catch err>Error: {err}</catch>
</async>

Unsafe interpolation

<unsafe>
  This is unsafe text: {text}
</unsafe>

<unsafe>
  This is unsafe text: {text}<br>
  But this is still safe <safe>{safeText}</safe>
</unsafe>

Everything is HTML friendly. My proposal doesn't contain any special chars in the names of Svelte tags. Also I think declarative code is easier to parse and validate. And full compatibility with HTML gives us such advantages as integration with code editors and linting tools. We may even write our own plugin for HTMLlint for example.

We may apply capitalization to new tags if we afraid of conflict with HTML spec. Other suggestions are welcome.

@constgen here is my sample with your syntax (in Sublime):
svelte-syntax3
I think the default highlighting doesn't make it clear what is HTML and what is not. It's nice though that the automatic tag matching works for closing if/loops, but it doesn't work for if blocks with elseif or else tags. Also the =<> chars in conditions are breaking some highlighting.
For me the 'like HTML' highlighting and verbosity are the parts I don't like.

Makes sense

It might just be resistance to change, but I think I like current syntax better than most of the suggestions here.

I appreciate that the syntax is currently similar to mustache, because every editor has a mustache syntax plugin, and while svelte's isn't exactly the same it's close enough for the highlighting to be nice. It is sort of a chicken and egg problem, because we can't exactly have editor plugins for a syntax that doesn't exist yet, but since there aren't yet any de facto plugins for v1 (at least for Atom, I can't speak very well to VSCode or Vim or Sublime others) I don't imagine plugins for v2 happening very soon either.

Personally, I like the idea of changing control flow tags to one curly, and adding some kind of character at the start of the inside ones like the {:else} mentioned above.

I'm in favor of keeping interpolation as two braces, I don't personally feel there's a problem with {{ value }}, it's familiar to people coming from any mustache-like, like Laravel's blade, or Vue. Similarly, I think {{{ html }}} is good as-is.

In summary, 1 brace for control flow type things ("these do things"), 2 for safe interpolation ("these display things on the page"), and 3 for unsafe interpolation ("so do these, but be careful") seems like a nice way to separate them to me.

I'm also strongly in favor of keeping quotes around attributes. In my opinion, having them optional but recommended (just like HTML for spaceless attribute values!) seems like the best way to go.

One of the things I like the most about svelte is that it feels more like HTML than React especially, and even Vue to a slight degree (though I'm not exactly sure why that is, that's probably just my own bias from the ways in which I've used the two). I don't see a lot of value in changing the syntax to be more React-like.

Edit again: The "do things" vs "display things" separation between 1 and 2 braces breaks down a bit for in-tag things like attributes, so that does make it a bit fuzzier.

For those worrying a lot about editor highlighting, it is _relatively_ easy to make a custom grammar for it. Here's what a grammar I quickly made looks like on one of the repl examples:

Ha, yeah I realize it's not that bad, I've made some before, but I still think there's value in having a well-maintained de facto one. But you're right it's not as big of a deal as I made it out to be.

I don't imagine plugins for v2 happening very soon either.

Part of the point in establishing a more permanent syntax is to make those plugins happen.

@UnwrittenFun that looks really great. You mentioned before that you'd been working on a language server β€” is that something you're in a position to share? Between that and the custom grammar shown above, we might be offer some decent 'official' plugins etc.

If anyone wants a handy summary of the changes (as they currently stand, at least!), there's one on the README for svelte-upgrade, which will rewrite your components for you:

https://github.com/sveltejs/svelte-upgrade/blob/master/README.md#svelte-v2-syntax-changes

{#each cats as cat key cat.name} -> what does key cat.name mean?

https://github.com/sveltejs/svelte-upgrade/blob/master/README.md#shorthand-properties

What's the shorthand for one-way vs. two-way binding? Or is that still a thing?

key cat.name is equivalent to the current @name. The syntax is changing to that so we can eventually support more complicated keyed lists where the key is any expression involving the list elements, rather than a specific property on each object.

@Rich-Harris So, these syntax changes will be in version 2, but when version 2 will be released? Do you've any plans?

@arxpoetica

What's the shorthand for one-way vs. two-way binding? Or is that still a thing?

Two-way is unchanged β€” <input bind:value> or <input bind:value='name'>. One way has changed:

<!-- before -->
<Foo bar={{bar}} />
<Foo :bar /> <!-- shorthand equivalent -->

<!-- after -->
<Foo bar={bar} />
<Foo {bar} /> <!-- shorthand equivalent -->

@PaulMaly as soon as humanly possible. Going to do as much work on it this weekend as time allows.

@Rich-Harris it needs a bit of a cleanup (and decoupling from vscode). I can shove it up on GitHub once I have done this

What about:

<input bind:value={name}>
<input bind:{value}>

For some consistency?

The format for directives is type:name=value or type:name where no value is necessary (i.e. refs, or shorthand bindings). In the case of bindings, it's something like

bind:expression1=expression2

Conceptually, this is like doing a = b in a reactive language. If it were this instead...

bind:expression1={expression2}

...then it's sort of like saying a = (whateverTheValueOfBIsRightNow) β€” let's say a = 42 β€” we're binding expression1 to the evaluation of expression2, rather than expression2 itself. Put another way, as I'm visualising data flowing through my components, I find it helpful to think of {...} as read-only windows onto reactively evaluated expressions, because in general expressions are read-only.

Probably not articulating myself very well here, but tl;dr is I think bind:value=name and bind:value are more logical.

After looking at the syntax as it stands now, I like it. I think the shorthand example should be updated to the example you provided a few comments up this page @Rich-Harris. It makes it more clear.

The one piece that feels confusing to me is they keyed array syntax.
{#each cats as cat key cat.name}
Perhaps with good syntax highlighting it will be better, but right now there are too many plain words that it is harder to understand. I'm not sure the solution. Perhaps one of these?

{#each cats as cat, key={cat.name}}
{#each cats as cat, @cat.name}

@jacwright I was waiting to see if anyone would bring that up... I kind of had the same feeling about key. Adding punctuation back is definitely a possibility. The comma might be excessive if you also had an index:

{#each cats as cat, i, key={cat.name}}

I'll throw a few more options on the table:

{#each cats as cat, i @cat.name}
{#each cats as cat, i | cat.name}
{#each cats as cat, i {cat.name}}
{#each cats as (cat, i) {cat.name}}
{#each cats as cat, i (cat.name)}
{#each cats as cat, i (key = cat.name)}

I think I prefer options that don't involve the }} curlies butting up against each other. None of them leap out as the 'obviously correct' answer ahead of the others, as far as I can see, though some are easier to type than others. Thoughts welcome!

tl;dr is I think bind:value=name and bind:value are more logical

Makes sense

I like {#each cats as cat, i, key={cat.name}} because I like to think of cat.name as an expression, but "no touching curlies" does seem like a good priority.

Beyond that, I lean towards {#each cats as cat, i @cat.name}

As long as I can do index as well as i.

Multiple cursor selection in various IDEs (cmd + d) can be really cumbersome when trying to select single letters because the letter I will be all over, whereas index is far more specific and each cursor selection will jump to the right thing.

{For each cat in cats where cat is identified by name}
  <span>{cat's name}</span>
{.}

Personally, I've always been fond of the syntax of the English language.

My vote is for:

{#each cats as cat, i (cat.name)}

The parens still imply that it's an expression, and no double curlies. And, it could support a space in that expression, unlike @cat.name.

Imagine {#each cats as cat, i (cat.items[i % 2])}
vs {#each cats as cat, i @cat.items[i % 2]}.

Think I agree with @hperrin. I'll start implementing {#each list as item, index (keyExpression)}. The only place it might look a bit weird is if you wanted to use the item as the key expression β€”

{#each words as word (word)}
  <p>{word}</p>
{/each}

β€” but I suspect that'd be true of whatever we chose.

Alright, this is implemented in 1.61. You can opt in with parser: 'v2', and use svelte-upgrade to update existing components. Thanks everyone!

Personally I find odd the use of {:else}

I think it can be a source of bugs for developers.

{else} can't be because of new bindings.
{#else} gonna look weird. Buy I would prefer this one since pound is already use for flow control.

@andreujuanc Why do you think it’ll be a source of bugs? What difference between this syntax change and any other?

i think its should be candidate for dev mode to catch possible user mistake

I think it's a change, and people are used to the prev version. I can be wrong, but muscle memory sometimes is hard to beat.

Another point against it, it's that the character is relatively smaller and less visible than pound, so eyeballing syntax might be tricky.
but hey I again. I can be wrong.

I do understand the use of it. I get the benefits. But something tells me that it's odd.

On the other hand for example I find AMAZING and well thought all the other changes.

I just think that these problems are common for any syntax changes. Not just for this one.

I leave this here for an inspiration Marko & NodeJS: STREAMING, ASYNC AND UI COMPONENTS! OH MY!

@constgen Basically, nothing new. I use all these things even with Ractive. One more bicycle.

I like declarative conditionals, loops, asyncs, etc.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matt3224 picture matt3224  Β·  3Comments

angelozehr picture angelozehr  Β·  3Comments

Rich-Harris picture Rich-Harris  Β·  3Comments

rob-balfre picture rob-balfre  Β·  3Comments

mmjmanders picture mmjmanders  Β·  3Comments