diff --git a/error-el.js b/error-el.js
new file mode 100644
index 0000000..3d7a005
--- /dev/null
+++ b/error-el.js
@@ -0,0 +1,51 @@
+const html = require('bel')
+const helpers = require('./element-helper')
+
+function errorContainer (opts) {
+ const classes = helpers.classes(['center', 'w-100', 'tc', 'red', 'f4', 'mt3', 'mb3'], opts)
+ const style = helpers.style('', opts)
+ const el = helpers.opts(html`
`, opts)
+ return el
+}
+
+function errorMessage (key, txt) {
+ return html`${txt}
`
+}
+
+function error (opts) {
+ opts = opts || {}
+ const messages = new Map()
+ const container = errorContainer(opts)
+
+ return {
+ render: () => container,
+ displayError,
+ removeError,
+ clear
+ }
+
+ function displayError (key, txt) {
+ if (messages.has(key)) {
+ const msgEl = getMsgDiv(key)
+ msgEl.innerText = txt
+ } else {
+ container.appendChild(errorMessage(key, txt))
+ }
+ messages.set(key, txt)
+ }
+
+ function removeError (key) {
+ messages.delete(key)
+ container.removeChild(getMsgDiv(key))
+ }
+
+ function clear () {
+ messages.forEach((_, key) => removeError(key))
+ }
+
+ function getMsgDiv (key) {
+ return container.querySelector(`div[data-for="${key}"]`)
+ }
+}
+
+module.exports = error
diff --git a/form-elements.js b/form-elements.js
index f8cbd99..eacd777 100644
--- a/form-elements.js
+++ b/form-elements.js
@@ -2,3 +2,4 @@ exports.input = require('./input-el')
exports.button = require('./button-el')
exports.label = require('./label-el')
exports.labeledInput = require('./labeled-input-el')
+exports.error = require('./error-el')
diff --git a/test/errors.spec.js b/test/errors.spec.js
new file mode 100644
index 0000000..f54f8ee
--- /dev/null
+++ b/test/errors.spec.js
@@ -0,0 +1,41 @@
+const test = require('tape')
+
+const error = require('../error-el.js')
+
+test('errors', (t) => {
+ const errA = error()
+ const $elA = errA.render()
+ const errB = error()
+ const $elB = errB.render()
+
+ t.equal($elA.children.length, 0, 'elA has no kids')
+ t.equal($elB.children.length, 0, 'elB has no kids')
+
+ errA.displayError('bar', 'beep')
+
+ t.equal($elA.children.length, 1, 'elA has a kid')
+ t.equal($elB.children.length, 0, 'elB has no kids')
+ t.equal($elA.children[0].innerText, 'beep', 'beeping')
+
+ errA.displayError('bar', 'moog')
+
+ t.equal($elA.children.length, 1, 'elA has a kid')
+ t.equal($elA.children[0].innerText, 'moog', 'mooging')
+
+ errA.removeError('bar')
+
+ t.equal($elA.children.length, 0, 'elA has no kids')
+ t.equal($elB.children.length, 0, 'elB has no kids')
+
+ errA.displayError('foo', 'boop')
+ errA.displayError('baz', 'shoop')
+
+ t.equal($elA.children.length, 2, 'elA has 2 kids')
+ t.equal($elA.children[0].innerText, 'boop', 'first we boop')
+ t.equal($elA.children[1].innerText, 'shoop', 'then we shoop')
+
+ errA.clear()
+
+ t.equal($elA.children.length, 0, 'elA has no kids')
+ t.end()
+})