diff --git a/js/src/common/components/Button.js b/js/src/common/components/Button.js
deleted file mode 100644
index 2d9bfc83d5..0000000000
--- a/js/src/common/components/Button.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import Component from '../Component';
-import icon from '../helpers/icon';
-import classList from '../utils/classList';
-import extract from '../utils/extract';
-import extractText from '../utils/extractText';
-import LoadingIndicator from './LoadingIndicator';
-
-/**
- * The `Button` component defines an element which, when clicked, performs an
- * action.
- *
- * ### Attrs
- *
- * - `icon` The name of the icon class. If specified, the button will be given a
- * 'has-icon' class name.
- * - `disabled` Whether or not the button is disabled. If truthy, the button
- * will be given a 'disabled' class name, and any `onclick` handler will be
- * removed.
- * - `loading` Whether or not the button should be in a disabled loading state.
- *
- * All other attrs will be assigned as attributes on the button element.
- *
- * Note that a Button has no default class names. This is because a Button can
- * be used to represent any generic clickable control, like a menu item.
- */
-export default class Button extends Component {
- view(vnode) {
- const attrs = Object.assign({}, this.attrs);
-
- attrs.type = attrs.type || 'button';
-
- // If a tooltip was provided for buttons without additional content, we also
- // use this tooltip as text for screen readers
- if (attrs.title && !vnode.children) {
- attrs['aria-label'] = attrs.title;
- }
-
- // If given a translation object, extract the text.
- if (typeof attrs.title === 'object') {
- attrs.title = extractText(attrs.title);
- }
-
- // If nothing else is provided, we use the textual button content as tooltip
- if (!attrs.title && vnode.children) {
- attrs.title = extractText(vnode.children);
- }
-
- const iconName = extract(attrs, 'icon');
-
- const loading = extract(attrs, 'loading');
- if (attrs.disabled || loading) {
- delete attrs.onclick;
- }
-
- attrs.className = classList([attrs.className, iconName && 'hasIcon', (attrs.disabled || loading) && 'disabled', loading && 'loading']);
-
- return ;
- }
-
- /**
- * Get the template for the button's content.
- *
- * @return {*}
- * @protected
- */
- getButtonContent(children) {
- const iconName = this.attrs.icon;
-
- return [
- iconName && iconName !== true ? icon(iconName, { className: 'Button-icon' }) : '',
- children ? {children} : '',
- this.attrs.loading ? : '',
- ];
- }
-}
diff --git a/js/src/common/components/Button.tsx b/js/src/common/components/Button.tsx
new file mode 100644
index 0000000000..bec7aa1d0b
--- /dev/null
+++ b/js/src/common/components/Button.tsx
@@ -0,0 +1,130 @@
+import type Mithril from 'mithril';
+import Component, { ComponentAttrs } from '../Component';
+import fireDebugWarning from '../helpers/fireDebugWarning';
+import icon from '../helpers/icon';
+import classList from '../utils/classList';
+import extractText from '../utils/extractText';
+import LoadingIndicator from './LoadingIndicator';
+
+export interface IButtonAttrs extends ComponentAttrs {
+ /**
+ * Class(es) of an optional icon to be rendered within the button.
+ *
+ * If provided, the button will gain a `has-icon` class.
+ */
+ icon?: string;
+ /**
+ * Disables button from user input.
+ *
+ * Default: `false`
+ */
+ disabled?: boolean;
+ /**
+ * Show a loading spinner within the button.
+ *
+ * If `true`, also disables the button.
+ *
+ * Default: `false`
+ */
+ loading?: boolean;
+ /**
+ * **DEPRECATED:** Please use the `aria-label` attribute instead. For tooltips, use
+ * the `` component.
+ *
+ * Accessible text for the button. This should always be present if the button only
+ * contains an icon.
+ *
+ * The textual content of this attribute is passed to the DOM element as `aria-label`.
+ *
+ * @deprecated
+ */
+ title?: string | Mithril.ChildArray;
+ /**
+ * Accessible text for the button. This should always be present if the button only
+ * contains an icon.
+ *
+ * The textual content of this attribute is passed to the DOM element as `aria-label`.
+ */
+ 'aria-label'?: string | Mithril.ChildArray;
+ /**
+ * Button type.
+ *
+ * Default: `"button"`
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type
+ */
+ type?: string;
+}
+
+/**
+ * The `Button` component defines an element which, when clicked, performs an
+ * action.
+ *
+ * Other attrs will be assigned as attributes on the `