{"id":11334,"library":"mithril","title":"Mithril.js","description":"Mithril.js is a modern, small, and fast client-side JavaScript framework primarily designed for building Single Page Applications. Currently at stable version 2.3.8, it maintains an active release cadence with regular patch updates and community-driven maintenance. Its key differentiators include a remarkably small bundle size (around 8.8 KiB gzipped), a highly performant virtual DOM diffing system, and built-in functionalities for routing and XHR requests, reducing the need for external libraries. Unlike some larger frameworks, Mithril.js focuses on providing core UI primitives without dictating an entire ecosystem, allowing developers more flexibility. It supports modern browsers (IE11, Firefox ESR, and the last two versions of Firefox, Edge, Safari, and Chrome) without requiring polyfills and can be used with or without build tools, although bundlers are recommended for production environments.","status":"active","version":"2.3.8","language":"javascript","source_language":"en","source_url":"https://github.com/MithrilJS/mithril.js","tags":["javascript"],"install":[{"cmd":"npm install mithril","lang":"bash","label":"npm"},{"cmd":"yarn add mithril","lang":"bash","label":"yarn"},{"cmd":"pnpm add mithril","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"For ESM projects, `m` is the default export. Use named imports for specific sub-modules in ESM. In CommonJS, `require('mithril')` is standard.","wrong":"const m = require('mithril')","symbol":"m","correct":"import m from 'mithril'"},{"note":"Most core functionalities like `mount`, `route`, `request` are properties of the default `m` object. While some are re-exported as named exports, accessing them via `m.<method>` is the idiomatic and most compatible approach across module types.","wrong":"import { mount } from 'mithril'","symbol":"mount","correct":"import m from 'mithril'; m.mount(document.body, Component)"},{"note":"Accessing routing utilities through the `m` object ensures consistent behavior, especially when dealing with auto-redraw. The CommonJS `require` pattern for sub-modules can work but is less common for `route` than importing the main `m` object.","wrong":"const route = require('mithril').route","symbol":"route","correct":"import m from 'mithril'; m.route(document.body, '/', routes)"},{"note":"Mithril ships with TypeScript definitions. `Vnode` is a common type to import for component definitions.","symbol":"Component Type","correct":"import m, { Vnode } from 'mithril'; function MyComponent(vnode: Vnode) { /* ... */ }"}],"quickstart":{"code":"import m from 'mithril';\n\ninterface MyComponentAttrs {\n  name: string;\n}\n\nconst MyComponent = {\n  count: 0, // Component local state\n  oninit: function(vnode: m.Vnode<MyComponentAttrs>) {\n    // Initialize state, cannot assign directly to vnode.state in v2+\n    vnode.state.count = 0;\n  },\n  view: function(vnode: m.Vnode<MyComponentAttrs>) {\n    return m('div', [\n      m('h1', `Hello, ${vnode.attrs.name}! Current count: ${vnode.state.count}`),\n      m('button', {\n        onclick: () => {\n          vnode.state.count++;\n        }\n      }, 'Increment'),\n      m('p', 'Click the button to increment the counter.')\n    ]);\n  }\n};\n\nm.mount(document.body, { view: () => m(MyComponent, { name: 'Mithril' }) });\n\n// To demonstrate routing (requires an element to mount routes to, e.g., <div id=\"app\"></div>)\n// const homeRoute = { view: () => m('h2', 'Welcome Home!') };\n// const aboutRoute = { view: () => m('h2', 'About Us') };\n// m.route(document.getElementById('app') || document.body, '/home', {\n//   '/home': homeRoute,\n//   '/about': aboutRoute\n// });","lang":"typescript","description":"This quickstart demonstrates a basic Mithril.js component with local state and event handling, then mounts it to the document body. It highlights how to define components, manage state, and render dynamic content."},"warnings":[{"fix":"Refactor `vnode.state = newValue` to `vnode.state.propertyName = newValue` and access state as `vnode.state.propertyName`.","message":"Direct assignment to `vnode.state` is no longer supported. In Mithril.js v2.x and later, `vnode.state` is an object, and properties should be assigned to it (e.g., `vnode.state.propertyName = value`) rather than reassigning `vnode.state` itself.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Replace `m.withAttr('attributeName', handler)` with a manual event handler that accesses `e.target.attributeName`. For example, `(e) => handler(e.target.value)` for input fields.","message":"The `m.withAttr` utility function has been removed in Mithril.js v2.x. This function was previously used for convenient event handler parameter extraction.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Applications must now explicitly handle server errors within the `extract` callback or the `.then()` chain. If encountering CORS issues, explicitly set `headers: {\"Content-Type\": \"text/plain\"}` in `m.request` options.","message":"The behavior of `m.request` for error handling has changed significantly in v2.x. If an `extract` callback is provided, `m.request` will no longer automatically reject the Promise for non-2xx/304 HTTP status codes (e.g., 4xx or 5xx server errors). Additionally, default `Content-Type` for JSON bodies might trigger unexpected CORS preflights.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure that your application logic accounts for redraws happening on the next animation frame. If immediate DOM updates are critical, reconsider your architectural approach or use synchronous DOM manipulation sparingly outside of Mithril's VDOM flow, understanding the risks.","message":"`m.redraw()` is always asynchronous in Mithril.js v2.x. The synchronous redraw behavior that was available in earlier versions (e.g., passing a truthy value to `m.redraw()`) has been removed.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"After any state changes resulting from these external events, you must explicitly call `m.redraw()` to signal Mithril.js to re-render the UI.","message":"Mithril.js's auto-redraw system does not trigger for external asynchronous events such as `setTimeout`, `setInterval`, raw Promises (not managed by `m.request`), or event handlers from third-party libraries (e.g., WebSockets).","severity":"gotcha","affected_versions":">=0.x.x"},{"fix":"Upgrade to Mithril.js version 2.0.3 or higher to patch this vulnerability.","message":"A prototype pollution vulnerability was identified and fixed in `m.parseQueryString`. Attackers could potentially manipulate object prototypes via crafted query strings.","severity":"security","affected_versions":"<2.0.3"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Implement defensive checks (e.g., `data && data.someProperty`), use optional chaining (`data?.someProperty`), or ensure data is available before rendering the affected part of the view.","cause":"Attempting to access a property on an `undefined` or `null` object within a view function, often due to asynchronous data loading not yet completing or typos in data paths.","error":"TypeError: Cannot read properties of undefined (reading 'someProperty')"},{"fix":"Ensure you are using the correct import syntax for your module environment (ESM: `import m from 'mithril'`, CJS: `const m = require('mithril')`). Verify that your build tools are correctly transpiling or bundling modules.","cause":"Incorrect module import syntax (e.g., using `require` in an ESM file, or incorrect named/default import) or trying to use Mithril before it's loaded.","error":"ReferenceError: m is not defined (or similar import errors like 'm is not a function')"},{"fix":"Check your network connection and the request URL. Verify server-side CORS headers are correctly configured (`Access-Control-Allow-Origin`, etc.). Ensure you have a `.catch()` block on your `m.request` promises to handle network and HTTP errors.","cause":"This error typically originates from `m.request` due to network issues, incorrect URL, or server-side CORS policies blocking the request. It can also appear if the promise rejection from `m.request` is not caught.","error":"Uncaught (in promise) TypeError: Failed to fetch"}],"ecosystem":"npm"}