diff --git a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx
new file mode 100644
index 000000000..cc4c118e6
--- /dev/null
+++ b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx
@@ -0,0 +1,30 @@
+import { Map as ImmutableMap } from 'immutable';
+import React from 'react';
+
+import { render, screen } from '../../../../jest/test-helpers';
+import CtaBanner from '../cta-banner';
+
+describe('', () => {
+ it('renders the banner', () => {
+ render();
+ expect(screen.getByTestId('cta-banner')).toHaveTextContent(/sign up/i);
+ });
+
+ describe('with a logged in user', () => {
+ it('renders empty', () => {
+ const store = { me: true };
+
+ render(, null, store);
+ expect(screen.queryAllByTestId('cta-banner')).toHaveLength(0);
+ });
+ });
+
+ describe('with singleUserMode enabled', () => {
+ it('renders empty', () => {
+ const store = { soapbox: ImmutableMap({ singleUserMode: true }) };
+
+ render(, null, store);
+ expect(screen.queryAllByTestId('cta-banner')).toHaveLength(0);
+ });
+ });
+});
diff --git a/app/soapbox/features/ui/components/cta-banner.tsx b/app/soapbox/features/ui/components/cta-banner.tsx
new file mode 100644
index 000000000..a1b5a8d8c
--- /dev/null
+++ b/app/soapbox/features/ui/components/cta-banner.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { FormattedMessage } from 'react-intl';
+
+import { Button, HStack, Stack, Text } from 'soapbox/components/ui';
+import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
+
+const CtaBanner = () => {
+ const { singleUserMode } = useSoapboxConfig();
+ const siteTitle = useAppSelector((state) => state.instance.title);
+ const me = useAppSelector((state) => state.me);
+
+ if (me || singleUserMode) return null;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CtaBanner;