# m(selector, attributes, children) - [Description](#description) - [Signature](#signature) - [How it works](#how-it-works) - [Flexibility](#flexibility) - [CSS selectors](#css-selectors) - [Attributes passed as the second argument](#attributes-passed-as-the-second-argument) - [DOM attributes](#dom-attributes) - [Style attribute](#style-attribute) - [Events](#events) - [Properties](#properties) - [Components](#components) - [Lifecycle methods](#lifecycle-methods) - [Keys](#keys) - [SVG and MathML](#svg-and-mathml) - [Making templates dynamic](#making-templates-dynamic) - [Converting HTML](#converting-html) - [Avoid anti-patterns](#avoid-anti-patterns) --- ### Description Represents an HTML element in a Mithril view ```javascript m("div", {class: "foo"}, "hello") // represents
hello
``` You can also [use HTML syntax](https://babeljs.io/repl/#?code=%2F**%20%40jsx%20m%20*%2F%0A%3Ch1%3EMy%20first%20app%3C%2Fh1%3E) via a Babel plugin. ```markup /** jsx m */
hello
``` --- ### Signature `vnode = m(selector, attrs, children)` Argument | Type | Required | Description ------------ | ------------------------------------------ | -------- | --- `selector` | `String|Object` | Yes | A CSS selector or a [component](components.md) `attrs` | `Object` | No | HTML attributes or element properties `children` | `Array|String|Number|Boolean` | No | Child [vnodes](vnodes.md#structure). Can be written as [splat arguments](signatures.md#splats) **returns** | `Vnode` | | A [vnode](vnodes.md#structure) [How to read signatures](signatures.md) --- ### How it works Mithril provides a hyperscript function `m()`, which allows expressing any HTML structure using javascript syntax. It accepts a `selector` string (required), an `attrs` object (optional) and a `children` array (optional). ```javascript m("div", {id: "box"}, "hello") // equivalent HTML: //
hello
``` The `m()` function does not actually return a DOM element. Instead it returns a [virtual DOM node](vnodes.md), or *vnode*, which is a javascript object that represents the DOM element to be created. ```javascript // a vnode var vnode = {tag: "div", attrs: {id: "box"}, children: [ /*...*/ ]} ``` To transform a vnode into an actual DOM element, use the [`m.render()`](render.md) function: ```javascript m.render(document.body, m("br")) // puts a
in ``` Calling `m.render()` multiple times does **not** recreate the DOM tree from scratch each time. Instead, each call will only make a change to a DOM tree if it is absolutely necessary to reflect the virtual DOM tree passed into the call. This behavior is desirable because recreating the DOM from scratch is very expensive, and causes issues such as loss of input focus, among other things. By contrast, updating the DOM only where necessary is comparatively much faster and makes it easier to maintain complex UIs that handle multiple user stories. --- ### Flexibility The `m()` function is both *polymorphic* and *variadic*. In other words, it's very flexible in what it expects as input parameters: ```javascript // simple tag m("div") //
// attributes and children are optional m("a", {id: "b"}) // m("span", "hello") // hello // tag with child nodes m("ul", [ // // array is optional m("ul", // ``` --- ### CSS selectors The first argument of `m()` can be any CSS selector that can describe an HTML element. It accepts any valid CSS combinations of `#` (id), `.` (class) and `[]` (attribute) syntax. ```javascript m("div#hello") //
m("section.container") //
m("input[type=text][placeholder=Name]") // m("a#exit.external[href='http://example.com']", "Leave") // Leave ``` If you omit the tag name, Mithril assumes a `div` tag. ```javascript m(".box.box-bordered") //
``` Typically, it's recommended that you use CSS selectors for static attributes (i.e. attributes whose value do not change), and pass an attributes object for dynamic attribute values. ```javascript var currentURL = "/" m("a.link[href=/]", { class: currentURL === "/" ? "selected" : "" }, "Home") // equivalent HTML: // Home ``` ### Attributes passed as the second argument You can pass attributes, properties, events and lifecycle hooks in the second, optional argument (see the next sections for details). ```JS m("button", { class: "my-button", onclick: function() {/* ... */}, oncreate: function() {/* ... */} }) ``` If the value of such an attribute is `null` or `undefined`, it is treated as if the attribute was absent. If there are class names in both first and second arguments of `m()`, they are merged together as you would expect. If the value of the class in the second argument is `null`or `undefined`, it is ignored. If another attribute is present in both the first and the second argument, the second one takes precedence even if it is is `null` or `undefined`. --- ### DOM attributes Mithril uses both the Javascript API and the DOM API (`setAttribute`) to resolve attributes. This means you can use both syntaxes to refer to attributes. For example, in the Javascript API, the `readonly` attribute is called `element.readOnly` (notice the uppercase). In Mithril, all of the following are supported: ```javascript m("input", {readonly: true}) // lowercase m("input", {readOnly: true}) // uppercase m("input[readonly]") m("input[readOnly]") ``` This even includes custom elements. For example, you can use [A-Frame](https://aframe.io/docs/0.8.0/introduction/) within Mithril, no problem! ```javascript m("a-scene", [ m("a-box", { position: "-1 0.5 -3", rotation: "0 45 0", color: "#4CC3D9", }), m("a-sphere", { position: "0 1.25 -5", radius: "1.25", color: "#EF2D5E", }), m("a-cylinder", { position: "1 0.75 -3", radius: "0.5", height: "1.5", color: "#FFC65D", }), m("a-plane", { position: "0 0 -4", rotation: "-90 0 0", width: "4", height: "4", color: "#7BC8A4", }), m("a-sky", { color: "#ECECEC", }), ]) ``` And yes, this translates to both attributes and properties, and it works just like they would in the DOM. Using [Brick's `brick-deck`](http://brick.mozilla.io/docs/brick-deck) as an example, they have a `selected-index` attribute with a corresponding `selectedIndex` getter/setter property. ```javascript m("brick-deck[selected-index=0]", [/* ... */]) // lowercase m("brick-deck[selectedIndex=0]", [/* ... */]) // uppercase // I know these look odd, but `brick-deck`'s `selectedIndex` property is a // string, not a number. m("brick-deck", {"selected-index": "0"}, [/* ... */]) m("brick-deck", {"selectedIndex": "0"}, [/* ... */]) ``` For custom elements, it doesn't auto-stringify properties, in case they are objects, numbers, or some other non-string value. So assuming you had some custom element `my-special-element` that has an `elem.whitelist` array getter/setter property, you could do this, and it'd work as you'd expect: ```javascript m("my-special-element", { whitelist: [ "https://example.com", "http://neverssl.com", "https://google.com", ], }) ``` If you have classes or IDs for those elements, the shorthands still work as you would expect. To pull another A-Frame example: ```javascript // These two are equivalent m("a-entity#player") m("a-entity", {id: "player"}) ``` Do note that all the properties with magic semantics, like lifecycle attributes, `onevent` handlers, `key`s, `class`, and `style`, those are still treated the same way they are for normal HTML elements. --- ### Style attribute Mithril supports both strings and objects as valid `style` values. In other words, all of the following are supported: ```javascript m("div", {style: "background:red;"}) m("div", {style: {background: "red"}}) m("div[style=background:red]") ``` Using a string as a `style` would overwrite all inline styles in the element if it is redrawn, and not only CSS rules whose values have changed. You can use both hyphenated CSS property names (like `background-color`) and camel cased DOM `style` property names (like `backgroundColor`). You can also define [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables), if your browser supports them. Mithril does not attempt to add units to number values. It simply stringifies them. --- ### Events Mithril supports event handler binding for all DOM events, including events whose specs do not define an `on${event}` property, such as `touchstart` ```javascript function doSomething(e) { console.log(e) } m("div", {onclick: doSomething}) ``` Mithril accepts functions and [EventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventListener) objects. So this will also work: ```javascript var clickListener = { handleEvent: function(e) { console.log(e) } } m("div", {onclick: clickListener}) ``` By default, when an event attached with hyperscript fires, this will trigger Mithril's auto-redraw after your event callback returns (assuming you are using `m.mount` or `m.route` instead of `m.render` directly). You can disable auto-redraw specifically for a single event by setting `e.redraw = false` on it: ```javascript m("div", { onclick: function(e) { // Prevent auto-redraw e.redraw = false } }) ``` --- ### Properties Mithril supports DOM functionality that is accessible via properties such as `