Skip to content

Template syntax alternative #89

@TheJaredWilcurt

Description

@TheJaredWilcurt

Is your feature request related to a problem? Please describe.

JSX/Lit/Uhtml/etc all look and act basically the same. For those that care about the very very subtle differences between them, it is nice to have those options, but another template syntax should be supported that differs more greatly to appeal to those coming from frameworks other than React.

Describe the solution you'd like

Dynamic attributes:

Dynamic attributes, or props, should be discerned by prefixing the attribute with a colon.

<a :href="someValue">Text</a>
<img
  :alt="'Avatar for ' + user.name"
  :src="'/avatars/' + user.id + '.jpg'"
/>

Boolean Attributes

Some HTML attributes are considered boolean attributes. Meaning they don't require a value to be valid, and their existence represents value. For example disabled, required, checked, etc.

In these cases, the syntax should accept a variable, and if truthy, it will append the attribute in the DOM.

<input :required="isRequired">
<!-- will produce one of the following -->
<input required>
<input>

Special attribute syntax for "class"

The most commonly used attribute in all of HTML, by a landslide, is class. Because it is so common, and has some common dynamic uses, we should support a few special syntax's to make life more convenient.

<!-- Works the same as all other dynamic attributes -->
<div :class="'card ' + favoriteColor"></div>
<div :class="success ? 'green' : 'red'"></div>

<!-- If an object is passed in, the key is considered a class, and only applied if the value is truthy -->
<div :class="{ 'is-active': someBoolean }"></div>

<!-- If an array is passed in, each item is evaluated to a class name, falsy items are filtered out -->
<div :class="[ 'card', favoriteColor, 'pt-lg', { 'is-active': isOnline } ]"></div>

Event Bindings:

Dynamic event bindings should be discerned by replacing the "on" prefix with an at-sign.

<button @click="someFunction">Click me</button>

Event Modifiers:

Several event modifiers should be supported to improve code readability. At the very least prevent and stop. For example

BAD:

<button @click="handleClick">Text</button>
function handleClick (evt) {
  evt.preventDefault();
  loadUserAvatar();
}

Can become the far more readable:
GOOD:

<button @click.prevent="loadUserAvatar">Text</button>

In Vue, "Handle X" is considered an anti-pattern, because the framework can handle most events for you, and it obscures the actual functionality being performed.

Inline expressions

Double curlies should be used to indicate a text node be created with the evaluated result of an expression.

<div>{{ someValue.toUpperCase() }}</div>

Two-Way data binding (text)

Two-way data binding is a common feature of framworks, like Polymer, Vue, and many others. This could be handled via an a-model attribute.

<input a-model="someValue">

This will set the value attribute of the input any time the someValue variable is modified. It would also add an event listener to the element for input events, retrieve the event.currentTarget.value and use that to update the value of the someValue variable.

This approach would be the same as doing:

<input :value="someValue" @input="(evt) => { someValue = evt.currentTarget.value }">

This matches the intuitive approach used by Vue 2. In Vue 3 it was changed to a less intuitive approach, in which it sets modelValue instead of value and expects update:modelValue instead of input. This change was made to allow applying multiple v-model's on an element. Something not possible in Vue 2, but also, not really needed, as you could emit an object if needed.

This would work on <input> elements with no type attribute (since it defaults to text) and most other input types (like type="email" or type="password", etc).

Two-way data binding (Boolean)

<input v-model="someValue" type="checkbox"> would be equivalent to

<input
  type="checkbox"
  :checked="someValue"
  @input="(evt) => { someValue = evt.currentTarget.checked }"
>

The 5 basic directives

You should be able to add a simple directive to your template to control common flow logic.

  • a-model
  • a-if
  • a-for
  • a-html
  • a-text
  • and a-show isn't needed but is cleaner than doing by hand

Examples:

  • <input a-model="value"> - See the two-way data binding section above
  • <div a-if="someBool"></div> - If someBool is false, this element is removed from the DOM. Can be performant by removing a large set of DOM nodes from memory when not needed.
  • <div a-show="someBool"></div> - If someBool is false, this attribute is given style="display: none". Can be more performant if toggling visibility on a lot of DOM nodes often
  • <div a-for="(item, index) in items"></div> - Creates an element (div in this case) for every item in the items array. item and index can be renamed to anything.
  • <div a-for="(value, key) in item"></div> - Creates an element for every key in the item object. value and key can be renamed to anything.
  • <div a-html="'<strong>Text</strong>'"></div> - Applies innerHTML, can be dangerous if it contains any data supplied by a user or network request, but also useful when the value is generated internally
  • <a a-text="'text'"></a> - Applies innerText, can be useful when you don't want additional whitespace that could occur when using returns and indentation in your code.

I probably should have started this wishlist issue with "Dear Santa,".

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions