What is the best syntax to use for declarative markup in HTML5?

  • Download Gist
Declarative Component Mapping Syntax Options.textile
Textile

Declarative Component Mapping Syntax Options

Language / Prior Art ‘Valid’ HTML HTML Mapping Example Example with Args
‘Valid’ CSS Selectable CSS Mapping CSS Select CSS Selector w Args
JavaScript MooTools Multiple instance Separate Args new Foo(element); new Bar(element) new Foo(element, {a:"a", bB:"b B", c:{c:1}}); new Bar(element, {d:"d"})
HTML attr Dojo <1.6 NO 1 Element per instance <div nsType=foo> <div nsType=foo a=a bB="b B" c.c=1>
CSS: A Single + Args [nsType] [nsType=Foo][a=a][bB~=b][bB~=B][c.c=1]
data-* Dojo 1.6+ YES 1 Element per instance <div data-ns="Foo"> <div data-ns="Foo" data-ns-a="a" data-ns-b-b="b B" data-ns-c.c="1">
CSS: A Single + Args [data-ns-type] [data-ns-type=Foo][data-ns-a=a][data-ns-bB~=b][data-ns-bB~=B][data-ns-c.c=1]
class & attr Apple iAd NO Multiple instances Combined Args <div class="ad-foo ad-bar"></div> <div class="ad-foo ad-bar" ad-title="MyBarButton"></div>
CSS: A+ Multi + Args .ad-foo, .ad-bar .ad-foo[ad-title], .ad-bar[ad-title]
data-* Hue Behavior YES Multiple instances Combined Args <div data-filters="ns.foo, ns.bar"> <div data-filters="ns.foo, ns.bar" data-a="a" data-b-b="b B" data-c='{"c":1}' data-d="d">
CSS: D All + Args [data-filters] [data-filters][data-a=a][data-bB~=b][data-bB~=B]
data-* & CSS YES Multiple instances Separate Args <div data-ns data-ns.foo data-ns.bar> <div data-ns data-ns.foo="a:a; b-b:b B; c{c:1}" data-ns.bar="d:d">
CSS: B Multi [data-ns] [data-ns.foo], [data-ns.bar]
attr & CSS NO Multiple instances Separate Args <div ns foo bar> <div ns foo="a:a; b-b:b B; c{c:1}" bar="d:d">
CSS: B Multi [ns] [ns][foo], [ns][bar]
data-* YES Multiple instances Separate Args <div data-ns="Foo Bar Baz"> <div data-ns="Foo Bar Baz" value=HTML data-foo.value=FOO data-bar.value=BAR>
CSS: A++ Multi + Multi Args [data-ns] [data-ns~=Foo][value=Frog]:not([data-foo.value]), [data-ns~=Foo][data-foo.value=Frog]
HTML attr NO Multiple instances Separate Args <div ns="Foo Bar Baz"> <div ns="Foo Bar Baz" value=HTML foo.value=FOO bar.value=BAR>
CSS: A++ Multi + Multi Args [ns] [ns~=Foo][value=Frog]:not([foo.value]), [ns~=Foo][foo.value=Frog]
data-* YES Multiple instances Separate Args <div data-ns="Foo, Bar, Baz"> <div data-ns="Foo:value(FOO), Bar:value(BAR), Baz:value(HTML)" value=HTML>
CSS: D- All [data-ns]
data-* YES Multiple instances Separate Args <div data-ns="Foo, Bar, Baz"> <div data-ns="Foo[value=FOO], Bar[value=BAR], Baz[value=HTML]" value=HTML>
CSS: D- All [data-ns]
xample.datagrid.1-1_data-attr.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<meta data-is=DataStore.JSON name=jsonStore content=dataItems.json>
 
<meta data-is=Model.Forest name=continentModel
content=jsonStore data-query=type:continent
data-root-id=continentRoot data-root-label=Continents data-children-attrs=children
>
 
<table data-is=DataGrid.Tree id=grid data-model=continentModel>
<thead>
<tr>
<th data-field=name style=width:auto>Name
<th data-field=population style=width:auto>Population
<th data-field=timezone style=width:auto>Timezone
</thead>
</table>
xample.datagrid.dojo15.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<span dojoType="dojo.data.ItemFileWriteStore"
jsId="jsonStore" data="dataItems"></span>
 
<div dojoType="dijit.tree.ForestStoreModel" jsId="continentModel"
store="jsonStore" query="{type:'continent'}"
rootId="continentRoot" rootLabel="Continents" childrenAttrs="children"></div>
 
<table jsid="grid" dojoType="dojox.grid.TreeGrid" class="grid" treeModel="continentModel">
<thead>
<tr>
<th field="name" width="auto">Name</th>
<th field="population" width="auto">Population</th>
<th field="timezone" width="auto">Timezone</th>
</tr>
</thead>
</table>
 
 
<a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/grid/tests/test_treegrid_model.html" title="dojox.grid.TreeGrid Model-based test">Example from Dojo Toolkit dojox.grid.TreeGrid Model-based test</a>

The ns would be replaced by whatever your namespace is, e.g. dojo, js, moo, whatever

This is interesting, but what about html5 component mapping where you use tags & types to map widgets to classes? I'm talking about input[type=range], button, aside.window, etc.

Make a gist with a specific example and link it here.

The first example column maps to being the equivalent of new Foo(element)
and the second example maps to new Foo(element, {arg1:1, arg2:2, etc:'...'})

A potential problem is that you may want to use a different value for the same key for different behaviors (Class instances).
e.g. new Foo(el,{value:'foo'}); new Bar(el,{value:'bar'})

One possible option that allows this is: <input data-be.foo="value:foo" data-be.bar="value:bar" value="htmlValue">

It's not possible with the iAd.js style: <input class="ad-foo ad-bar" ad-value="foo" value="htmlValue">
There's no way to pass 'bar' to Bar :(

A major advantage of using the combined args approach.
It allows you to use those attributes and values in your CSS Selectors directly!

.ad-buttonbar[ad-awesomeness~=glorious] { border:10px solid gold }

The problem with it is that if you want multiple instances per element, each instance constructor gets access to the exact same set of key/value pairs and there's no way to pass value=foo to Foo and value=bar to Bar

unless...

Maybe that could be solved by using a cascade of attribute value importance ala CSS.

<input instantiate-with-me="Foo Bar Baz" name=HTML value=HTML foo.value=FOO bar.value=BAR>

Would map to

new Foo(el,{name:'HTML', value:'FOO'})
new Bar(el,{name:'HTML', value:'BAR'})
new Baz(el,{name:'HTML', value:'HTML'})

Then in your CSS you could target it thusly:

[instantiate-with-me~=Baz][name=HTML][value=Frog]:not([baz.value]),
[instantiate-with-me~=Baz][name=HTML][baz.value=Frog]{
    background: green
}

That does require :not() (which isn't supported in IE8), so that may be an issue.

You can use selectivizr.com to add support for attr selectors in IE6, but I'd like to avoid requiring selectivizr for IE8.

It'd be nice if there was a single selector you could use to grab all elements that should be processed in some way. Either in CSS, delegated events or actually instantiating stuff on domready.

<form i-am-special><label i-am-special><input i-am-special></label></form>

[i-am-special] {background:green}

HTML.addEvent('click:relay([i-am-special])', handleClickSpecial)

re: [instantiate-with-me~=Baz]

How expensive are CSS regexp matches? Souders's Even Faster Web Sites talks about the performance challenges of having many CSS rules, and using lots of regexp here would only seem to make that problem worse.

How about this:

<div ui class="keyword1 keyword2 keyword3 ...">

where each keyword can be a class name, or a modifier to another keyword's class.

Example:

<div ui class="select-table tree-view multiple-select">

Example CSS selectors:

[ui]
.key1[ui]
.key2.key3[ui]

Another approach, separating the main class and its modifiers more cleanly:

<div ui="select-table" class="tree-view multiple-select">  
.tree-view.multiple-select[ui=select-table]

Either of these approaches takes advantage of browsers' native, automatic function of splitting class names on whitespace, so we don't need to use regexp CSS selectors.

.foo === [class~=foo]

~= is an attribute value operator for selecting from space separated values. There is no RegExp happing in the browser's native CSS engine.

Therefore [ui~=foo][ui~=bar] should be no more expensive than .foo.bar since .foo.bar === [class~=foo][class~=bar].

I'd like to avoid keeping stuff in class (as iAds.js has unfortunately chosen to do) since everything else on earth already uses class for everything under the sun.
I believe that it would be too hard to keep track of what is a behavior className and what is a style className.

I guess you could namespace all your classnames as iAds do (e.g. class="ad-foo ad-bar ad-baz-of-doom-and-stuff") but I'd like to continue exploring the custom attribute path.

I'm referring to each browser's own implementation of application of CSS rules to HTML rendering. It's great to hear that Slick doesn't use RegExp for =~, but if the browsers do, then large DOMs with large sets of =~ CSS may take a long time to render and modify.

This is why we need to do actual benchmarks against real browsers and get hard numbers. Without hard data we cannot make assumptions about how slow or fast any of these options are.
This thread is mostly interested in the functionality and features alone. Performance data for attribute ~= selectors vs className selectors in CSS as well as document.querySelector would be very interesting.

Thomas, I don't understand how a single element would instantiate many instances.

My concept of an element is an instance of a single class. The widget would inherit from many or be composed of many, but it's a single widget. Not sure if you follow, but allowing multiple instantiations is smelly to me. Very glue code like. Perhaps, correct me. Here's an example: div[ns-type="human"][ns-type="??"] what else should/could be instantiated? Scientist? That's a human. Any verbs belongs to the human or any objects that belong to the human.

So that's the first thing we should tackle, imo.

I don't like the idea of strictly mapping "instances" to filters, this pattern lends itself to more than just an interface in to element based classes. I regularly use filters on parent elements and delegate events down to children elements (Thomas, think atlas tagging).

Ibolmo, I use several filters on one element, it could be a draggable htmltable, which is neither a human or scientist.

I have more to say but this iPad keyboard is not cooperating, I'll be back!

I'd probably make a Table class that composes a HTMLTable and a Draggable instance on that table. Then it'd be a simple declaration on the html.

Yeah, but if you keep it 1:1 like that you'll end up creating lots and lots of silly little throwaway classes just so that you can combine a few totally unrelated things.

The purpose of this spec isn't to impose a programming style on you, it's simply the best way of decorating HTML so that it is easy for JS and CSS to get at all that data. Your code can (and should) do whatever you want and impose whatever programming conventions and paradigms you prefer.

For an application I wrote last year, I used HTML like:

<div class="datagrid" rel="{'foo':'bar'}">

I am actually starting a new application in the new year which will use a similar system, exactly this type of thing, but I am thinking going with Aaron's method of having a single attribute (such as [data-type=datagrid]) for performance, just run that selector the once, but retaining the options as a JSON object which is parsed and passed to the class as options.

Very interested in this topic of conversation and I can / will benchmark some ideas over the coming weeks.

Please don't use rel for that. Ew :P
I'm so thrilled that the HTML5 spec has finally legitimized data-* attributes!

Yeah, I will be switching to a different attribute for sure :D it is definitely 'ew'!

The first feature I wanted after writing my version of this pattern, Element.Behaviors, was the ability to pass arguments in. I decided to give Slick a shot at parsing the filters and so far I like it, it looks like this:

<fieldset data-filter="toggles">
    <button>one</button>
    <button>two</button>
    <button>three</button>
</fieldset>

<div data-filter="panels[units=%] window[close][minimize][resizable]">
    <div>Panel 1</div>
    <div>Panel 2</div>
</div>

Another thought I've had, and seen around town, is putting in some JSON for the arguments into a another data-attribute. The panels/window example would look something like this:

<div 
    data-filter="panels window"
    data-panels-options="{'units':'%'}"
    data-window-options="{'buttons':['close','minimize'], 'resizable':true}">

    <div>Panel 1</div>
    <div>Panel 2</div>

</div>

This is awesome because you get the power of JSON, like passing in arrays and stuff, also no external parser is required, like Slick, just use JSON.parse. I think the HTML is easier to follow as well.

However, I recently needed to apply the same filter with different arguments to an element. Element.Behaviors doesn't support this yet, so I've had to work around it by writing unnecessary filters that do the same thing, my next iteration will support this, like so:

<body data-filter="track[event=click][selector='a[data-linkid]'] track[event=mouseenter][selector='.info']">

Unfortunately, you can't do this with the JSON + extra data-attributes approach:

<table data-filter="track track"
    data-track-options="{'event':'click', 'selector':'a[data-linkid]'}"
    data-track-options="oh crap, can't filter this twice ...">
</table>

Actually, you could sort of combine the two ideas, and just tell the filter where to find the options:

<table data-filter="track:data-track1ops track:data-track2ops"
    data-track1opts="{'event':'click', 'selector':'a[data-linkid]'}"
    data-track2opts="{'event':'mouseenter', 'selector':'.more'}">
</table>

Okay, now that new year's eve is over, I can post what I've been thinking about all night (I gave up on being cool a long time ago).

http://jsfiddle.net/rpflorence/33sUS/

I really like this.

The CSS also gets an A (and sometimes A++) because as long as you provide some arguments, you can style with [data-ns], if you don't provide the extra argument containing attribute, you can still style with [data-filter~=ns]

rpflorence, that's pretty cool :D.

Do you think, though, that we're blurring the line of separation? In my concept: CSS is style/view, HTML is layout/model, and JS is the controller. Adding JSON to the HTML, for example, seems like you're creeping JS into the HTML -- I know it's just a format, but you know what I mean.

Also, some of the options defined in the HTML are clearly CSS/style/view related. Perhaps this should have gone into CSS? Then the API could provide you with a parsed stylesheet (perhaps with Thomas' Sheet.js).

hehe hope it doesn't come as confrontational. just wondering what your opinion is on the separation matter.

I'm not really sure about JSON. It makes the HTML kind of ugly. I am voting for any kind of unobtrusive HTML.

I really like Ryan's example. ++.

I am all for the usage of JSON, it is very flexible, and I think it's easier to read (a lot easier) than loads of data- attributes, which would also add up to quite a bit for large documents, not to mention performance in good ol' IE.

@ibolmo

Do you think, though, that we're blurring the line of separation?...

The logic is still separate from the presentation, all this is doing is describing the presentation with JSON. Pretend that we're trying to create the new HTML5 "video" tag before it existed. HTML passes "arguments" in to the browser's video tag "filter". But we can't do it the way HTML does and still write valid code.

Also, some of the options defined in the HTML are clearly CSS/style/view related

Just an example to discuss the API. (not sure which example your talking about ...)

Current (HTML) API to send arguments to "widgets"

HTML

<video 
  audio=muted
  height=9
  width=16
  controls
  loop
  preload>
  <source src="foo.ogg">
  <source src="foo.mp4">
</video>

CSS

video {
  /* styles */
}

It's invalid to use these attributes in a pre-video tag world. We could do it like this, and mimick it:

Lots of data attributes

HTML

<div 
  data-filter=video
  data-audio=muted
  data-height=9
  data-width=19
  data-controls
  data-loop
  data-preload>
  <span data-source="foo.ogg"></span>
  <span data-source="foo.mp4"></span>
</div>

CSS

[data-filter~=video]{
  /* styles */
}

JSON style

HTML

<div
  data-filter=video
  data-video='{
    "audio": "muted",
    "height": 9,
    "width": 19,
    "controls": true,
    "loop": true,
    "preload": true,
    "sources":["foo.ogg", "foo.mp4"]
  }'></div>

CSS

[data-video]{
  /* styles */
}

CSS String Style

HTML

<div data-filter="video[audio=muted][height=9][width=19][controls][loop][preload][source=foo.ogg][source=foo.mp4]"></div>

CSS

[good luck ...]

... seems like you're creeping JS into the HTML

Those are the options I've both considered and used in recent projects. Not sure what other options there are to describe the presentation of advanced elements, other than describing them in the JavaScript, which is not where it belongs.

@cpojer

I'm not really sure about JSON. It makes the HTML kind of ugly

I didn't know HTML wasn't already completely ugly :D I had the same thought, actually, until I used it several times. I think it's just more unfamiliar than ugly.

I am voting for any kind of unobtrusive HTML

Do you consider this JSON obtrusive?

Why I like using JSON

  • It's a flexible, concise format
  • You can parse it natively (excluding old browsers, ofc)
  • It ends up in JavaScript, might as well start it as JavaScript

I started using JSON for this kind of stuff almost two years ago and I have grown to dislike it. It might be slightly fewer bytes but having data-* properties on an element is much more expressive. I prefer expressiveness but I can see the concerns regarding file size.

Another reason I like JSON is that most element-based classes have two constructor arguments: an element, and an options object.

A conceivably useful script would be a Class Mutator, that automatically throws your class into this declarative HTML pattern. With JSON, your options API--whether in JavaScript or in a data-attribute--is coherent.

Using JSON as attribute values is not declarative HTML, it's embedded JavaScript.


A couple more ideas:

More Human-Readable:

<div data-filter="video"
data-video="audio=muted, height=9, width=19, controls, loop, preload,
source=foo.ogg, source=foo.mp4"></div>

Pros:

  • HTML-like key=value format
  • No brackets => better-looking => easier to read
  • Easily to parse

Cons:

  • Not as flexible as JSON
  • Not directly parsable by Slick

More HTML-Like:

<div
  data-filter="video"
  data-video-audio="audio"
  data-video-muted
  data-video-height="9"
  data-video-width="9"
  data-video-controls
  data-video-loop
  data-video-preload
  data-video-source="foo.ogg,foo.mp4"
></div>

Pros:

  • Fits HTML attribute="value" pattern

Cons:

  • Too verbose and redundant (too many data-video- prefixes)
  • Not as human-readable as grouping the attributes in one data-video attribute
  • Not as performant in older browsers without HTMLElement.dataset support (must get several attribute values from the element itself -- expensive)

I prefer the simple, concise, Human-Readable format.

More CSS-like:

<div data-filter="video"
data-video="
  audio: muted;
  height: 9;
  width: 19;
  controls: true;
  loop: true;
  preload: true;
  sources: foo.ogg, foo.mp4;
"></div>

Pros:

  • Existing precedent for using CSS in HTML attribute (style)
  • Human-readable

Cons:

  • Parsing CSS-like syntax into JS object is a bit of a challenge, but maybe Sheet.js can do it?

Cascading Behavior Attributes:

Wacky idea: How about some way to define classes of commonly-used Behavior attribute sets, as in CSS?

Somebody has to set precedent, embedded CSS for CSS features, embedded JSON for JavaScript features.

In all sane proposals we embed some sort of data interchange format.

Also, in your last example, replace semi-colons for commas, dynamically add the brackets and you've got JSON. Might as well use an existing, flexible format that you don't have to parse, document, or maintain.

/shrug

I thought about the CSS-to-JSON conversion (it led to propose the CSS-like option), but the conversion isn't so simple. Following the procedure you suggested on my example does not yield the intended result:

{
  audio: muted,
  height: 9,
  width: 19,
  controls: true,
  loop: true,
  preload: true,
  sources: foo.ogg,
  foo.mp4
}

That said, I would be more in favor of JSON as attribute value if the brackets could be omitted from HTML and added dynamically on interpretation.

What about ..

<div class="video">
    <param name="is_muted" value="false"/>
    <param name="height" value="9px"/>
    <param name="width" value="19px"/>
    <param name="controls" value="true"/>
    <param name="loop" value="true"/>
    <param name="preload" value="true"/>
    <param name="sources" value="foo.ogg, foo.mp4"/>
</div>

I thought about param tags, but one thing I really don't want to do is prescribe something that doesn't validate.

JSON makes even more sense when you consider serverside integration e.g.

<div data-ns="FooBar" data-foo-bar='#{ foo_bar.to_json }'>

I would personally MUCH prefer a CSS-like syntax, but using JSON is just such a huge win in so many pragmatic ways that I simply can't argue against it.
Maybe I could allow for CSS-like as the default but if the first character is a { then parse it as JSON, but that may be too much confusion in the declarative API.

When coding in HTML you shouldn't have to think of it as passing an options object to a new Constructor(el, options).
That kind of thinking leads to declarative APIs that are are far too low-level and implementation-specific.

My goal is to create declarative HTML APIs that feels like native HTML features and then most of the actual JS code will feel like polyfill.

For most things it makes more sense to have separate real attributes.
e.g.

<button
  title="Clicking this button will send the current email that you've been working on all night"
  data-alt-working="Sending…"
  data-alt-invalid="Cannot Send"
><b data-default>Send Email<b></button>

Cf. http://jsfiddle.net/SubtleGradient/DWcgY/embedded/result,html,css/

In this example I am declaring what other values this button will have in each possible state.
The HTML shouldn't have to know or care if it's CSS or JS or the browser itself that actually handles swapping these things out, if at all.

I chose to use attributes for these values instead of additional tags inside the button so that the Web 1.0 view still makes sense. You can't have a button look as if it's in 5 separate states and still make sense to anyone. It also seems to map into the existing HTML convention of the title and alt attributes.

Another option would be to have behaviors be more like CSS.
You can declare style or behavior on an element directly e.g.

<button style="color:blue;" behavior="click:winTheWorld;">Click for great win</button>

Or declare all your style and behavior in separate files. e.g.

<button class="winsTheWorld">Click for great win</button>
/* CSS */
.winsTheWorld {color:blue;}
/* BE */
.winsTheWorld:click {win: theWorld;}

Or declare all your style and behavior in the same file using STYLE and special SCRIPT tags. e.g.

<button class="winsTheWorld">Click for great win</button>
<style> .winsTheWorld {color:blue;} </style>
<script type="text/behavior"> .winsTheWorld:click {win: theWorld;} </script>

Taking a step back, there are multiple different concepts going on here.

Content-based Webpage. Markup your content with tags. Add meta data using attributes. Add style using CSS. Add behaviors using a blob of domready code or a behavior sheet. UPDATED: See https://gist.github.com/765730 for the thread about Behavior Sheets.

<button class="isFancy" data-tooltip="This will make winning happen for you!">Click for great win</button>
/* CSS */ .isFancy:hover {background:url(prancing-ponies.gif);}
/* BE */ .isFancy:hover {tooltip:attr(data-tooltip)}

Data-backed Webapp. Expose content via REST / JSON. Define your app layout and widgets using declarative syntax (HTML + special attributes) or function syntax (JS). e.g.

<span id="addressBookModel" myType="DataModel" type="text/json" source="addressbook.json"></span>
<input type=search store="addressBookModel" myType="Filter" placeholder="Filter this list!">
<table id="addressBookView" dataStore="addressBookModel">
    <thead>
        <tr field="firstName">First Name</tr>
        <tr field="lastName">Last Name</tr>
        <tr field="iq">Awesomeness Quotient</tr>
    </thead>
</table>
<button something-goes-here plural="Delete selected Emails">Delete this Email</button>
<button something-goes-here>New Email</button>

I think a lot of the differences in syntax options comes from the very different use cases that each of us are planning to use this stuff for.

It's important to recognize up front if you're building a website or a webapp and then choose the programming patterns that make the most sense for that specific project. Trying to mash a webapp into the programming model of a website will be very bad, and vice-versa. Also consider the implications of using data-backed widgets inside of page-based websites.

Don't try to make every project conform to the programming patterns that you're already comfortable with.
Just imagine trying to build a realtime system monitoring application using website-style programming patterns.

I'm not sure it even makes sense to program webapps and websites using the same exact programming patterns.

It's not BSS, it's CBS (Cascading Behavior Sheets).

I really like the Data-backed Webapp concept and proposed syntax. That's what I intended to do in Maui. (And nice use of element IDs, by the way. /inside joke ;)

Just one note, if we use another file format that externally defines the behavior it kind of defeats the purpose of having this kind of functionality. The options must be tied to the HTML it comes with. Otherwise for highly dynamic content it might create yet another request (if you have several files with behaviors defined) and it isn't much better than just going with the "large domready block".

I just wanted to highlight that any kind of implementation must also be able to work well with updated content, not just on domready. So if you have a selector to retrieve all elements that need a behavior, you need to filter out the elements that have a behavior applied already. Something like [data-behavior]:not([data-behavior-attached]). Just sayin' for the record.

I'd allow 2 styles (<ul data-slideshow-theme="golden" data-slideshow='{"src":"/data/images.json","speed":"JSON"}'>]), for the sake of controllable CSS ([data-slideshow-theme="golden"]) but also to allow servers-side generation of interchangeable data. Both sources would be merged into one option object.

This caters to both concepts and can be applied on content and app-based structures.

I see some edge cases that don't work after the element-2-instance pattern, requiring event delegation or other pattern. That's why I like the onAttach, onDetach approach I saw. We can also make the callback very customizable, allowing simple concepts like events ('ajax': { delegate: true, click: function(event, options) { stuff(); } }) but also classes (slideshow: App.Slideshow or provided via dependency injection slideshow: 'App/Slideshow')

Previously I was using json as the attribute value for settings of some behavior like an fx because I thought it was the most logical approach. Later I dropped it and started using lots of data- attributes describing each param separately. Reason I dropped the json was because I read somewhere in the mootools docs/blog that such an approach (dunno in what class, maybe some Fx or Validator class) was going to be dropped as it wasn't valid html..?!

UPDATE: ah yes, here it's in Aaron's Form.Validator: http://mootools.net/docs/more/Forms/Form.Validator
"[...] You can use a property called "validatorProps" and pass in Json values if you like, but this is not valid XHTML. This is deprecated but will continue to be supported."

However, I sometimes prefix the data-value attributes for a filter like:
data-filter="video" data-video-width="9" data-video-source="foo.mp4" ...
else you don't know which attribute applies to the correct filter (e.g. when you apply two). With json you can put one object into 1 data- attribute... so... too many thoughts

http://jsfiddle.net/SubtleGradient/DWcgY/embedded/result,html,css/
Been using things like that as well.. would you consider this hackish/ugly? I kind of like it, but it can't work without js for IE7 and such

@digitarald & @Rolf-nl

I believe that using both separate attributes as well as separate options attributes are the way to go, but strictly separated by what they're for.
Use attributes when you are adding meta data about the tag and its contents. Use an options attribute when you are passing specific options to some specific behavior.

e.g.

<img src="Cheddar.png" alt="Pungent Orange Cheddar Cheese"
    data-type="food-dairy-cheese-cheddar" data-smell="pungent" data-color="orange"
    data-behavior="Dance Sing"
    data-behavior-dance='{type:"waltz", speed:"slow"}'
    data-behavior-sing='{type:"show tune", speed:"fast"}'
/>

or with minimal HTML and CSS-style syntax…

<img src=Cheddar.png alt="Pungent Orange Cheddar Cheese"
    data-type=food-dairy-cheese-cheddar data-smell=pungent data-color=orange
    data-behavior="Dance Sing"
    data-behavior-dance="type:waltz; speed:slow"
    data-behavior-sing="type:show tune; speed:fast;"
>

Has many attributes.
Has many behaviors.
Each Behavior has up to one options attribute.

And for extra credit… CSS!

[data-type|=food-dairy] { background-image: url(cow.png) }
[data-type|=food-dairy][data-behavior~=Dance]{ background-image: url(dancing-cow.png) }

Maybe we need separate terminology for behaviors that effect how you interact with it vs behaviors that effect what it is.

e.g. Attributes on a DataGrid is really meta data about what it is, so even though that effects how you interact with it, it is more suitable as separate attributes since it is describing what that element is.

And then with a separate behavior sheet.

UPDATED: See https://gist.github.com/765730 for the thread about Behavior Sheets.

Not sure what the point of the behavior sheet is, while interesting, seems no different than just cranking out some slick selectors and calling element methods on the results (like we sort of did on goconnect).

Maybe I am not thinking abstract enough, but I saw the mapping for data-[class]="[options-table]" and data-[class]-[options-key]="[options-value]" … which than maps to our classy new Class(element, options).

class could be either mapped in a sheet, auto-detected from the name or, just a thought, referenced in the HTML (<div data-require="table=App.Core.Table; zebra=App.More.Zebra" data-table="{…}" data-zebra-selectable="true">). The latter provides a nice way to avoid all kind of sheets, since all references are kept in one place.

I don't feel comfortable with the sheets, they need to be generic enough to be external and than would need to define resources shared within the whole application. Having them inline as attributes

Yes, my thoughts too. Or is w3c coming with something like a behavior sheet recommendation (I don't keep up with the specs/updates)? It's a nice idea, but I wouldn't use it. JSON for options is probably the easiest way to go as it already works and it's relatively easy to implement. I like Ryan's idea in his Element.Filters that the choice of parser is optional.
I'd like to hear cpojer's thoughts as well.

@ryan, goconnect is goconnect.org?

Thomas, I'd like to see more practical examples than smelling and singing cheese ;)

@digitarald++ for the mapping, which feels like it should be. Though I also like it when you can describe your custom behavior/filter that might instantiate more than one classes or a singleton that does a bunch of stuff. Kind of like Ryan's Element.Filters

Thomas, how can you sing a fast show tune and dance a slow waltz at the same time? or did you forgot the chain option? Plus, I wouldn't mix low culture hamburger cheddar with high culture waltz stuff.. (naah, on 2nd thought, waltz is simple == low culture.. mix is good)

Dancing and Singing have nothing to do with what that element IS but is more about how that thing behaves.

e.g.

Bob is a Person and acts like a Clown

<div name=bob is=Person age=37 height="5feet 3in" acts-like="Clown" clown='{"nose-color":"Red", "nose-sound":"honk"}'>

May map to something like…

new Person(element, { name:"bob", age:37, height:"5feet 3in" });
new Clown(element, { name:"bob", age:37, height:"5feet 3in", "nose-color":"Red", "nose-sound":"honk" });

Edgar is a Cow and acts like a Person

<div name=edgar is=Cow age=37 acts-like="Person" clown='{"height":"5feet 3in"}'>

May map to something like…

new Cow(element, { name:"edgar", age:37 });
new Person(element, { name:"edgar", age:37, height:"5feet 3in" });

Ralph is a Person and acts like a Ninja

etc…

So all the attributes of an element could merge in all the specific attributes of that 'acts-like' thing and give you a single object. But all that is kindof OT for this thread. I think I have solved the original question that this thread posed, that is, what is the best syntax to use for declarative markup.

@digitarald Mapping of alias to specific JS namespace should happen in JS, not HTML. e.g. SubtleBehavior.defineAlias({zebra: My.NameSpace.Of.Doom.Zembra, foo:Foo, bar:MySuperBar})

See https://gist.github.com/765730 for the thread about Behavior Sheets.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.