diff --git a/frontend/src/ts/components/common/Button.tsx b/frontend/src/ts/components/common/Button.tsx
index dafd7f7f7e5a..92c79cc0ddde 100644
--- a/frontend/src/ts/components/common/Button.tsx
+++ b/frontend/src/ts/components/common/Button.tsx
@@ -7,6 +7,8 @@ import { Fa, FaProps } from "./Fa";
type BaseProps = {
text?: string;
fa?: FaProps;
+ /** Leading icon for icons that are not available in Font Awesome. Rendered in the same slot as `fa`. */
+ icon?: JSXElement;
class?: string;
variant?: "text" | "button";
children?: JSXElement;
@@ -48,6 +50,7 @@ export function Button(props: ButtonProps | AnchorProps): JSXElement {
+ {props.icon}
{props.text}
{props.children}
>
diff --git a/frontend/src/ts/components/common/XIcon.tsx b/frontend/src/ts/components/common/XIcon.tsx
new file mode 100644
index 000000000000..1952df0baa73
--- /dev/null
+++ b/frontend/src/ts/components/common/XIcon.tsx
@@ -0,0 +1,34 @@
+import { JSXElement } from "solid-js";
+
+import { cn } from "../../utils/cn";
+
+type XIconProps = {
+ fixedWidth?: boolean;
+ class?: string;
+};
+
+/**
+ * The X (formerly Twitter) logo. Font Awesome only ships this icon from v6
+ * onwards, so it is inlined here instead of going through `Fa`.
+ */
+export function XIcon(props: XIconProps): JSXElement {
+ return (
+
+
+
+ );
+}
diff --git a/frontend/src/ts/components/layout/footer/Footer.tsx b/frontend/src/ts/components/layout/footer/Footer.tsx
index 3b0484c4dff3..c276c289fd46 100644
--- a/frontend/src/ts/components/layout/footer/Footer.tsx
+++ b/frontend/src/ts/components/layout/footer/Footer.tsx
@@ -5,6 +5,7 @@ import { showModal } from "../../../states/modals";
import { getFocus } from "../../../states/test";
import { cn } from "../../../utils/cn";
import { Button } from "../../common/Button";
+import { XIcon } from "../../common/XIcon";
import { Keytips } from "./Keytips";
import { ThemeIndicator } from "./ThemeIndicator";
import { VersionButton } from "./VersionButton";
@@ -64,12 +65,8 @@ export function Footer(): JSXElement {
/>
}
href="https://x.com/monkeytype"
/>
}
href="https://x.com/monkeytype"
class="w-full p-8"
/>
diff --git a/frontend/src/ts/components/pages/profile/UserDetails.tsx b/frontend/src/ts/components/pages/profile/UserDetails.tsx
index 70fe2fbb8b3b..fed79e08c62f 100644
--- a/frontend/src/ts/components/pages/profile/UserDetails.tsx
+++ b/frontend/src/ts/components/pages/profile/UserDetails.tsx
@@ -33,6 +33,7 @@ import { Button } from "../../common/Button";
import { DiscordAvatar } from "../../common/DiscordAvatar";
import { UserBadge } from "../../common/UserBadge";
import { UserFlags } from "../../common/UserFlags";
+import { XIcon } from "../../common/XIcon";
import { EditProfile } from "../../modals/EditProfileModal";
type Variant = "basic" | "hasSocials" | "hasBioOrKeyboard" | "full";
@@ -525,7 +526,7 @@ function Socials(props: {
}
href={`https://x.com/${props.socials?.twitter}`}
balloon={{ text: props.socials?.twitter ?? "" }}
/>