diff --git a/native/components/loadable-button.react.js b/native/components/loadable-button.react.js
new file mode 100644
--- /dev/null
+++ b/native/components/loadable-button.react.js
@@ -0,0 +1,80 @@
+// @flow
+
+import * as React from 'react';
+import { View, ActivityIndicator } from 'react-native';
+
+import Button from './button.react.js';
+import { useStyles, useColors } from '../themes/colors.js';
+
+type LoadableContentProps = {
+ +children: React.Node,
+ +isLoading: boolean,
+};
+
+function LoadableContent(props: LoadableContentProps): React.Node {
+ const { children, isLoading } = props;
+
+ const styles = useStyles(unboundStyles);
+ const colors = useColors();
+
+ const buttonContentContainerStyles = React.useMemo(() => {
+ const result = [styles.container];
+
+ if (isLoading) {
+ result.push(styles.containerLoading);
+ }
+
+ return result;
+ }, [isLoading, styles.container, styles.containerLoading]);
+
+ const loadingSpinner = React.useMemo(() => {
+ if (!isLoading) {
+ return null;
+ }
+
+ return (
+
+ );
+ }, [colors.whiteText, isLoading, styles.loadingSpinner]);
+
+ return (
+ <>
+ {children}
+ {loadingSpinner}
+ >
+ );
+}
+
+type Props = {
+ ...React.ElementConfig,
+ +isLoading: boolean,
+};
+
+function LoadableButton(props: Props): React.Node {
+ const { isLoading, children, ...rest } = props;
+
+ return (
+
+ );
+}
+
+const unboundStyles = {
+ container: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ containerLoading: {
+ opacity: 0,
+ },
+ loadingSpinner: {
+ position: 'absolute',
+ },
+};
+
+export default LoadableButton;