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,".
enhancement