diff --git a/app/javascript/mastodon/features/reaction_deck/index.jsx b/app/javascript/mastodon/features/reaction_deck/_index.jsx
similarity index 100%
rename from app/javascript/mastodon/features/reaction_deck/index.jsx
rename to app/javascript/mastodon/features/reaction_deck/_index.jsx
diff --git a/app/javascript/mastodon/features/reaction_deck/index.tsx b/app/javascript/mastodon/features/reaction_deck/index.tsx
new file mode 100644
index 0000000000..d7cef29c25
--- /dev/null
+++ b/app/javascript/mastodon/features/reaction_deck/index.tsx
@@ -0,0 +1,172 @@
+/* eslint-disable @typescript-eslint/no-unsafe-return,
+ @typescript-eslint/no-explicit-any,
+ @typescript-eslint/no-unsafe-call,
+ @typescript-eslint/no-unsafe-member-access,
+ @typescript-eslint/no-unsafe-assignment */
+
+import type { ReactNode } from 'react';
+import { useCallback } from 'react';
+
+import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
+
+import { Helmet } from 'react-helmet';
+
+import EmojiReactionIcon from '@/material-icons/400-24px/mood.svg?react';
+import { updateReactionDeck } from 'mastodon/actions/reaction_deck';
+import { Button } from 'mastodon/components/button';
+import { Column } from 'mastodon/components/column';
+import { ColumnHeader } from 'mastodon/components/column_header';
+import { LoadingIndicator } from 'mastodon/components/loading_indicator';
+import EmojiPickerDropdown from 'mastodon/features/compose/containers/emoji_picker_dropdown_container';
+import { autoPlayGif } from 'mastodon/initial_state';
+import { useAppDispatch, useAppSelector } from 'mastodon/store';
+
+import emojify from '../emoji/emoji';
+
+const messages = defineMessages({
+ reaction_deck_add: { id: 'reaction_deck.add', defaultMessage: 'Add' },
+ heading: { id: 'column.reaction_deck', defaultMessage: 'Reaction deck' },
+});
+
+const ReactionEmoji: React.FC<{
+ index: number;
+ emoji: string;
+ emojiMap: any;
+ onRemove: (index: number) => void;
+}> = ({ index, emoji, emojiMap, onRemove }) => {
+ const handleRemove = useCallback(() => {
+ onRemove(index);
+ }, [index, onRemove]);
+
+ let content: ReactNode;
+ const mapEmoji = emojiMap.find((e: any) => e.get('shortcode') === emoji);
+
+ if (mapEmoji) {
+ const filename = autoPlayGif
+ ? mapEmoji.get('url')
+ : mapEmoji.get('static_url');
+ const shortCode = `:${emoji}:`;
+
+ content = (
+
+ );
+ } else {
+ const html = { __html: emojify(emoji) };
+ content = ;
+ }
+
+ return (
+