diff --git a/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.css b/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.css
new file mode 100644
--- /dev/null
+++ b/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.css
@@ -0,0 +1,21 @@
+.inputLabel {
+  color: var(--text-background-primary-default);
+  margin-bottom: 8px;
+}
+
+.dropdownInputContainer {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.errorMessage {
+  text-align: center;
+  color: var(--text-background-danger-default);
+  font-size: var(--s-font-14);
+  visibility: hidden;
+}
+
+.errorMessageVisible {
+  visibility: visible;
+}
diff --git a/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js b/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js
new file mode 100644
--- /dev/null
+++ b/web/tag-farcaster-channel/create-farcaster-channel-tag-modal.react.js
@@ -0,0 +1,135 @@
+// @flow
+
+import classNames from 'classnames';
+import invariant from 'invariant';
+import * as React from 'react';
+
+import { useModalContext } from 'lib/components/modal-provider.react.js';
+import { NeynarClientContext } from 'lib/components/neynar-client-provider.react.js';
+import {
+  tagFarcasterChannelErrorMessages,
+  useCreateFarcasterChannelTag,
+} from 'lib/shared/community-utils.js';
+import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js';
+
+import css from './create-farcaster-channel-tag-modal.css';
+import Button, { buttonThemes } from '../components/button.react.js';
+import Dropdown, { type DropdownOption } from '../components/dropdown.react.js';
+import Modal from '../modals/modal.react.js';
+
+type Props = {
+  +communityID: string,
+};
+
+function CreateFarcasterChannelTagModal(props: Props): React.Node {
+  const { communityID } = props;
+
+  const { popModal } = useModalContext();
+
+  const fid = useCurrentUserFID();
+  invariant(fid, 'FID should be set');
+
+  const neynarClientContext = React.useContext(NeynarClientContext);
+  invariant(neynarClientContext, 'NeynarClientContext is missing');
+
+  const { client } = neynarClientContext;
+
+  const [channelOptions, setChannelOptions] = React.useState<
+    $ReadOnlyArray<DropdownOption>,
+  >([]);
+  const [selectedOption, setSelectedOption] = React.useState<?string>(null);
+  const [error, setError] = React.useState<?string>(null);
+
+  React.useEffect(() => {
+    void (async () => {
+      const channels = await client.fetchFollowedFarcasterChannels(fid);
+
+      const sortedChannels = channels
+        .sort((a, b) => a.id.localeCompare(b.id))
+        .map(channel => ({
+          id: channel.id,
+          name: `/${channel.id}`,
+        }));
+
+      setChannelOptions(sortedChannels);
+    })();
+  }, [client, fid]);
+
+  const onChangeSelectedOption = React.useCallback((option: string) => {
+    setError(null);
+    setSelectedOption(option);
+  }, []);
+
+  const { createTag, isLoading } = useCreateFarcasterChannelTag(
+    communityID,
+    setError,
+    popModal,
+  );
+
+  const onClickTagChannel = React.useCallback(() => {
+    if (!selectedOption) {
+      return;
+    }
+
+    createTag(selectedOption);
+  }, [createTag, selectedOption]);
+
+  const buttonDisabled = isLoading || !selectedOption;
+
+  const primaryButton = React.useMemo(() => {
+    return (
+      <Button
+        variant="filled"
+        buttonColor={buttonThemes.standard}
+        onClick={onClickTagChannel}
+        disabled={buttonDisabled}
+      >
+        Create tag
+      </Button>
+    );
+  }, [onClickTagChannel, buttonDisabled]);
+
+  const errorMessageClassName = classNames(css.errorMessage, {
+    [css.errorMessageVisible]: error,
+  });
+
+  const errorMessage =
+    error && tagFarcasterChannelErrorMessages[error]
+      ? tagFarcasterChannelErrorMessages[error]
+      : 'Unknown error.';
+
+  const createFarcasterChannelTagModal = React.useMemo(
+    () => (
+      <Modal
+        name="Create a tag"
+        onClose={popModal}
+        size="large"
+        primaryButton={primaryButton}
+      >
+        <div className={css.inputLabel}>Farcaster channel</div>
+        <div className={css.dropdownInputContainer}>
+          <Dropdown
+            options={channelOptions}
+            defaultLabel="Select a channel"
+            activeSelection={selectedOption}
+            setActiveSelection={onChangeSelectedOption}
+          />
+        </div>
+        <div className={errorMessageClassName}>{errorMessage}</div>
+      </Modal>
+    ),
+    [
+      channelOptions,
+      errorMessage,
+      errorMessageClassName,
+      onChangeSelectedOption,
+      popModal,
+      primaryButton,
+      selectedOption,
+    ],
+  );
+
+  return createFarcasterChannelTagModal;
+}
+
+export default CreateFarcasterChannelTagModal;
diff --git a/web/tag-farcaster-channel/tag-farcaster-channel-modal.react.js b/web/tag-farcaster-channel/tag-farcaster-channel-modal.react.js
--- a/web/tag-farcaster-channel/tag-farcaster-channel-modal.react.js
+++ b/web/tag-farcaster-channel/tag-farcaster-channel-modal.react.js
@@ -10,8 +10,10 @@
 } from 'lib/shared/community-utils.js';
 import type { CommunityInfo } from 'lib/types/community-types.js';
 
+import CreateFarcasterChannelTagModal from './create-farcaster-channel-tag-modal.react.js';
 import RemoveTagButton from './remove-tag-button.react.js';
 import css from './tag-farcaster-channel-modal.css';
+import Button, { buttonThemes } from '../components/button.react.js';
 import Modal from '../modals/modal.react.js';
 import { useSelector } from '../redux/redux-utils.js';
 
@@ -22,7 +24,7 @@
 function TagFarcasterChannelModal(props: Props): React.Node {
   const { communityID } = props;
 
-  const { popModal } = useModalContext();
+  const { popModal, pushModal } = useModalContext();
 
   const communityInfo: ?CommunityInfo = useSelector(
     state => state.communityStore.communityInfos[communityID],
@@ -30,6 +32,12 @@
 
   const [removeTagError, setRemoveTagError] = React.useState<?string>();
 
+  const openCreateFarcasterChannelTagModal = React.useCallback(
+    () =>
+      pushModal(<CreateFarcasterChannelTagModal communityID={communityID} />),
+    [communityID, pushModal],
+  );
+
   const channelNameTextContent = React.useMemo(() => {
     if (!communityInfo?.farcasterChannelID) {
       return (
@@ -56,9 +64,21 @@
         />
       );
     }
-    // TODO: Implement TagChannelButton
-    return null;
-  }, [communityID, communityInfo?.farcasterChannelID]);
+
+    return (
+      <Button
+        variant="filled"
+        buttonColor={buttonThemes.standard}
+        onClick={openCreateFarcasterChannelTagModal}
+      >
+        Tag channel
+      </Button>
+    );
+  }, [
+    communityID,
+    communityInfo?.farcasterChannelID,
+    openCreateFarcasterChannelTagModal,
+  ]);
 
   const errorMessageClassName = classNames(css.errorMessage, {
     [css.errorMessageVisible]: removeTagError,