diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs
index 9929642539..e4bc5645b6 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs
@@ -13,6 +13,7 @@ using osu.Game.Online.API.Requests.Responses;
 using osu.Game.Online.Chat;
 using osu.Game.Overlays;
 using osu.Game.Overlays.Chat.ChannelList;
+using osu.Game.Overlays.Chat.Listing;
 
 namespace osu.Game.Tests.Visual.Online
 {
@@ -118,35 +119,37 @@ namespace osu.Game.Tests.Visual.Online
         {
             AddStep("Unread Selected", () =>
             {
-                if (selected.Value != null)
+                if (validItem)
                     channelList.GetItem(selected.Value).Unread.Value = true;
             });
 
             AddStep("Read Selected", () =>
             {
-                if (selected.Value != null)
+                if (validItem)
                     channelList.GetItem(selected.Value).Unread.Value = false;
             });
 
             AddStep("Add Mention Selected", () =>
             {
-                if (selected.Value != null)
+                if (validItem)
                     channelList.GetItem(selected.Value).Mentions.Value++;
             });
 
             AddStep("Add 98 Mentions Selected", () =>
             {
-                if (selected.Value != null)
+                if (validItem)
                     channelList.GetItem(selected.Value).Mentions.Value += 98;
             });
 
             AddStep("Clear Mentions Selected", () =>
             {
-                if (selected.Value != null)
+                if (validItem)
                     channelList.GetItem(selected.Value).Mentions.Value = 0;
             });
         }
 
+        private bool validItem => selected.Value != null && !(selected.Value is ChannelListing.ChannelListingChannel);
+
         private Channel createRandomPublicChannel()
         {
             int id = RNG.Next(0, 10000);
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs
index 3e3c8122b3..e27db00003 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs
@@ -376,7 +376,7 @@ namespace osu.Game.Tests.Visual.Online
             AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
             AddStep("Click drawable channel", () => clickDrawable(currentDrawableChannel));
             AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
-            AddStep("Click selector", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelListSelector>().Single()));
+            AddStep("Click selector", () => clickDrawable(channelSelectorButton));
             AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
             AddStep("Click listing", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelListing>().Single()));
             AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
@@ -397,6 +397,7 @@ namespace osu.Game.Tests.Visual.Online
                 chatOverlay.SlowLoading = true;
             });
             AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1));
+            AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1)));
             AddAssert("Channel 1 loading", () => !channelIsVisible && chatOverlay.GetSlowLoadingChannel(testChannel1).LoadState == LoadState.Loading);
 
             AddStep("Join channel 2", () => channelManager.JoinChannel(testChannel2));
@@ -437,6 +438,9 @@ namespace osu.Game.Tests.Visual.Online
         private ChatOverlayTopBar chatOverlayTopBar =>
             chatOverlay.ChildrenOfType<ChatOverlayTopBar>().Single();
 
+        private ChannelListItem channelSelectorButton =>
+            chatOverlay.ChildrenOfType<ChannelListItem>().Single(item => item.Channel is ChannelListing.ChannelListingChannel);
+
         private void clickDrawable(Drawable d)
         {
             InputManager.MoveMouseTo(d);
diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs
index 1fe784f68b..b7d67de04d 100644
--- a/osu.Game/Online/Chat/ChannelManager.cs
+++ b/osu.Game/Online/Chat/ChannelManager.cs
@@ -14,6 +14,7 @@ using osu.Game.Input;
 using osu.Game.Online.API;
 using osu.Game.Online.API.Requests;
 using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays.Chat.Listing;
 using osu.Game.Overlays.Chat.Tabs;
 
 namespace osu.Game.Online.Chat
@@ -133,7 +134,9 @@ namespace osu.Game.Online.Chat
 
         private void currentChannelChanged(ValueChangedEvent<Channel> e)
         {
-            if (!(e.NewValue is ChannelSelectorTabItem.ChannelSelectorTabChannel))
+            bool isSelectorChannel = e.NewValue is ChannelSelectorTabItem.ChannelSelectorTabChannel || e.NewValue is ChannelListing.ChannelListingChannel;
+
+            if (!isSelectorChannel)
                 JoinChannel(e.NewValue);
         }
 
@@ -420,11 +423,10 @@ namespace osu.Game.Online.Chat
         /// Joins a channel if it has not already been joined. Must be called from the update thread.
         /// </summary>
         /// <param name="channel">The channel to join.</param>
-        /// <param name="setCurrent">Set the channel to join as the current channel if the current channel is null.</param>
         /// <returns>The joined channel. Note that this may not match the parameter channel as it is a backed object.</returns>
-        public Channel JoinChannel(Channel channel, bool setCurrent = true) => joinChannel(channel, true, setCurrent);
+        public Channel JoinChannel(Channel channel) => joinChannel(channel, true);
 
-        private Channel joinChannel(Channel channel, bool fetchInitialMessages = false, bool setCurrent = true)
+        private Channel joinChannel(Channel channel, bool fetchInitialMessages = false)
         {
             if (channel == null) return null;
 
@@ -440,7 +442,7 @@ namespace osu.Game.Online.Chat
                     case ChannelType.Multiplayer:
                         // join is implicit. happens when you join a multiplayer game.
                         // this will probably change in the future.
-                        joinChannel(channel, fetchInitialMessages, setCurrent);
+                        joinChannel(channel, fetchInitialMessages);
                         return channel;
 
                     case ChannelType.PM:
@@ -461,7 +463,7 @@ namespace osu.Game.Online.Chat
 
                     default:
                         var req = new JoinChannelRequest(channel);
-                        req.Success += () => joinChannel(channel, fetchInitialMessages, setCurrent);
+                        req.Success += () => joinChannel(channel, fetchInitialMessages);
                         req.Failure += ex => LeaveChannel(channel);
                         api.Queue(req);
                         return channel;
@@ -473,8 +475,7 @@ namespace osu.Game.Online.Chat
                     this.fetchInitialMessages(channel);
             }
 
-            if (setCurrent)
-                CurrentChannel.Value ??= channel;
+            CurrentChannel.Value ??= channel;
 
             return channel;
         }
diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs
index 6bdf5ee084..d1ceae604c 100644
--- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs
+++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs
@@ -13,18 +13,22 @@ using osu.Game.Graphics;
 using osu.Game.Graphics.Containers;
 using osu.Game.Graphics.Sprites;
 using osu.Game.Online.Chat;
+using osu.Game.Overlays.Chat.Listing;
 
 namespace osu.Game.Overlays.Chat.ChannelList
 {
     public class ChannelList : Container
     {
-        public Action<Channel?>? OnRequestSelect;
+        public Action<Channel>? OnRequestSelect;
         public Action<Channel>? OnRequestLeave;
 
+        public readonly ChannelListing.ChannelListingChannel ChannelListingChannel = new ChannelListing.ChannelListingChannel();
+
         private readonly Dictionary<Channel, ChannelListItem> channelMap = new Dictionary<Channel, ChannelListItem>();
 
         private ChannelListItemFlow publicChannelFlow = null!;
         private ChannelListItemFlow privateChannelFlow = null!;
+        private ChannelListItem selector = null!;
 
         [BackgroundDependencyLoader]
         private void load(OverlayColourProvider colourProvider)
@@ -50,16 +54,17 @@ namespace osu.Game.Overlays.Chat.ChannelList
                         Children = new Drawable[]
                         {
                             publicChannelFlow = new ChannelListItemFlow("CHANNELS"),
-                            new ChannelListSelector
+                            selector = new ChannelListItem(ChannelListingChannel)
                             {
                                 Margin = new MarginPadding { Bottom = 10 },
-                                Action = () => OnRequestSelect?.Invoke(null),
                             },
                             privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"),
                         },
                     },
                 },
             };
+
+            selector.OnRequestSelect += chan => OnRequestSelect?.Invoke(chan);
         }
 
         public void AddChannel(Channel channel)
diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs
index dd571c9ad9..9ab0c2792a 100644
--- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs
+++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs
@@ -15,6 +15,7 @@ using osu.Game.Graphics;
 using osu.Game.Graphics.Containers;
 using osu.Game.Graphics.Sprites;
 using osu.Game.Online.Chat;
+using osu.Game.Overlays.Chat.Listing;
 using osu.Game.Users.Drawables;
 using osuTK;
 
@@ -34,7 +35,7 @@ namespace osu.Game.Overlays.Chat.ChannelList
         private Box hoverBox = null!;
         private Box selectBox = null!;
         private OsuSpriteText text = null!;
-        private ChannelListItemCloseButton close = null!;
+        private ChannelListItemCloseButton? close;
 
         [Resolved]
         private Bindable<Channel> selectedChannel { get; set; } = null!;
@@ -83,7 +84,7 @@ namespace osu.Game.Overlays.Chat.ChannelList
                         },
                         Content = new[]
                         {
-                            new[]
+                            new Drawable?[]
                             {
                                 createIcon(),
                                 text = new OsuSpriteText
@@ -97,20 +98,8 @@ namespace osu.Game.Overlays.Chat.ChannelList
                                     RelativeSizeAxes = Axes.X,
                                     Truncate = true,
                                 },
-                                new ChannelListItemMentionPill
-                                {
-                                    Anchor = Anchor.CentreLeft,
-                                    Origin = Anchor.CentreLeft,
-                                    Margin = new MarginPadding { Right = 3 },
-                                    Mentions = { BindTarget = Mentions },
-                                },
-                                close = new ChannelListItemCloseButton
-                                {
-                                    Anchor = Anchor.CentreLeft,
-                                    Origin = Anchor.CentreLeft,
-                                    Margin = new MarginPadding { Right = 3 },
-                                    Action = () => OnRequestLeave?.Invoke(Channel),
-                                }
+                                createMentionPill(),
+                                close = createCloseButton(),
                             }
                         },
                     },
@@ -131,21 +120,23 @@ namespace osu.Game.Overlays.Chat.ChannelList
         protected override bool OnHover(HoverEvent e)
         {
             hoverBox.FadeIn(300, Easing.OutQuint);
-            close.FadeIn(300, Easing.OutQuint);
+            close?.FadeIn(300, Easing.OutQuint);
+
             return base.OnHover(e);
         }
 
         protected override void OnHoverLost(HoverLostEvent e)
         {
             hoverBox.FadeOut(200, Easing.OutQuint);
-            close.FadeOut(200, Easing.OutQuint);
+            close?.FadeOut(200, Easing.OutQuint);
+
             base.OnHoverLost(e);
         }
 
-        private Drawable createIcon()
+        private UpdateableAvatar? createIcon()
         {
             if (Channel.Type != ChannelType.PM)
-                return Drawable.Empty();
+                return null;
 
             return new UpdateableAvatar(Channel.Users.First(), isInteractive: false)
             {
@@ -158,6 +149,34 @@ namespace osu.Game.Overlays.Chat.ChannelList
             };
         }
 
+        private ChannelListItemMentionPill? createMentionPill()
+        {
+            if (isSelector)
+                return null;
+
+            return new ChannelListItemMentionPill
+            {
+                Anchor = Anchor.CentreLeft,
+                Origin = Anchor.CentreLeft,
+                Margin = new MarginPadding { Right = 3 },
+                Mentions = { BindTarget = Mentions },
+            };
+        }
+
+        private ChannelListItemCloseButton? createCloseButton()
+        {
+            if (isSelector)
+                return null;
+
+            return new ChannelListItemCloseButton
+            {
+                Anchor = Anchor.CentreLeft,
+                Origin = Anchor.CentreLeft,
+                Margin = new MarginPadding { Right = 3 },
+                Action = () => OnRequestLeave?.Invoke(Channel),
+            };
+        }
+
         private void updateState()
         {
             bool selected = selectedChannel.Value == Channel;
@@ -172,5 +191,7 @@ namespace osu.Game.Overlays.Chat.ChannelList
             else
                 text.FadeColour(colourProvider.Light3, 200, Easing.OutQuint);
         }
+
+        private bool isSelector => Channel is ChannelListing.ChannelListingChannel;
     }
 }
diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs
deleted file mode 100644
index a07aad2041..0000000000
--- a/osu.Game/Overlays/Chat/ChannelList/ChannelListSelector.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-#nullable enable
-
-using osu.Framework.Allocation;
-using osu.Framework.Bindables;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Input.Events;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Online.Chat;
-
-namespace osu.Game.Overlays.Chat.ChannelList
-{
-    public class ChannelListSelector : OsuClickableContainer
-    {
-        private Box hoverBox = null!;
-        private Box selectBox = null!;
-        private OsuSpriteText text = null!;
-
-        [Resolved]
-        private Bindable<Channel> currentChannel { get; set; } = null!;
-
-        [Resolved]
-        private OverlayColourProvider colourProvider { get; set; } = null!;
-
-        [BackgroundDependencyLoader]
-        private void load(OverlayColourProvider colourProvider)
-        {
-            Height = 30;
-            RelativeSizeAxes = Axes.X;
-
-            Children = new Drawable[]
-            {
-                hoverBox = new Box
-                {
-                    RelativeSizeAxes = Axes.Both,
-                    Colour = colourProvider.Background3,
-                    Alpha = 0f,
-                },
-                selectBox = new Box
-                {
-                    RelativeSizeAxes = Axes.Both,
-                    Colour = colourProvider.Background4,
-                    Alpha = 0f,
-                },
-                new Container
-                {
-                    RelativeSizeAxes = Axes.Both,
-                    Padding = new MarginPadding { Left = 18, Right = 10 },
-                    Child = text = new OsuSpriteText
-                    {
-                        Anchor = Anchor.CentreLeft,
-                        Origin = Anchor.CentreLeft,
-                        Text = "Add more channels",
-                        Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold),
-                        Colour = colourProvider.Light3,
-                        Margin = new MarginPadding { Bottom = 2 },
-                        RelativeSizeAxes = Axes.X,
-                        Truncate = true,
-                    },
-                },
-            };
-        }
-
-        protected override void LoadComplete()
-        {
-            base.LoadComplete();
-
-            currentChannel.BindValueChanged(channel =>
-            {
-                // This logic should be handled by the chat overlay rather than this component.
-                // Selected state should be moved to an abstract class and shared with ChannelListItem.
-                if (channel.NewValue == null)
-                {
-                    text.FadeColour(colourProvider.Content1, 300, Easing.OutQuint);
-                    selectBox.FadeIn(300, Easing.OutQuint);
-                }
-                else
-                {
-                    text.FadeColour(colourProvider.Light3, 200, Easing.OutQuint);
-                    selectBox.FadeOut(200, Easing.OutQuint);
-                }
-            }, true);
-        }
-
-        protected override bool OnHover(HoverEvent e)
-        {
-            hoverBox.FadeIn(300, Easing.OutQuint);
-            return base.OnHover(e);
-        }
-
-        protected override void OnHoverLost(HoverLostEvent e)
-        {
-            hoverBox.FadeOut(200, Easing.OutQuint);
-            base.OnHoverLost(e);
-        }
-    }
-}
diff --git a/osu.Game/Overlays/Chat/Listing/ChannelListing.cs b/osu.Game/Overlays/Chat/Listing/ChannelListing.cs
index 732c78de15..8a5bc18cbf 100644
--- a/osu.Game/Overlays/Chat/Listing/ChannelListing.cs
+++ b/osu.Game/Overlays/Chat/Listing/ChannelListing.cs
@@ -75,5 +75,14 @@ namespace osu.Game.Overlays.Chat.Listing
         protected override void PopIn() => this.FadeIn();
 
         protected override void PopOut() => this.FadeOut();
+
+        public class ChannelListingChannel : Channel
+        {
+            public ChannelListingChannel()
+            {
+                Name = "Add more channels";
+                Type = ChannelType.System;
+            }
+        }
     }
 }
diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs
index b2c1f6858c..ef479ea21b 100644
--- a/osu.Game/Overlays/ChatOverlayV2.cs
+++ b/osu.Game/Overlays/ChatOverlayV2.cs
@@ -65,6 +65,9 @@ namespace osu.Game.Overlays
         [Cached]
         private readonly Bindable<Channel> currentChannel = new Bindable<Channel>();
 
+        private readonly IBindableList<Channel> availableChannels = new BindableList<Channel>();
+        private readonly IBindableList<Channel> joinedChannels = new BindableList<Channel>();
+
         public ChatOverlayV2()
         {
             Height = default_chat_height;
@@ -150,14 +153,18 @@ namespace osu.Game.Overlays
             chatHeight.BindValueChanged(height => { Height = height.NewValue; }, true);
 
             currentChannel.BindTo(channelManager.CurrentChannel);
-            channelManager.CurrentChannel.BindValueChanged(currentChannelChanged, true);
-            channelManager.JoinedChannels.BindCollectionChanged(joinedChannelsChanged, true);
-            channelManager.AvailableChannels.BindCollectionChanged(availableChannelsChanged, true);
+            currentChannel.BindValueChanged(currentChannelChanged, true);
+
+            joinedChannels.BindTo(channelManager.JoinedChannels);
+            joinedChannels.BindCollectionChanged(joinedChannelsChanged, true);
+
+            availableChannels.BindTo(channelManager.AvailableChannels);
+            availableChannels.BindCollectionChanged(availableChannelsChanged, true);
 
             channelList.OnRequestSelect += channel => channelManager.CurrentChannel.Value = channel;
             channelList.OnRequestLeave += channel => channelManager.LeaveChannel(channel);
 
-            channelListing.OnRequestJoin += channel => channelManager.JoinChannel(channel, false);
+            channelListing.OnRequestJoin += channel => channelManager.JoinChannel(channel);
             channelListing.OnRequestLeave += channel => channelManager.LeaveChannel(channel);
 
             textBar.OnSearchTermsChanged += searchTerms => channelListing.SearchTerm = searchTerms;
@@ -176,7 +183,7 @@ namespace osu.Game.Overlays
             if (currentChannel.Value?.Id != channel.Id)
             {
                 if (!channel.Joined.Value)
-                    channel = channelManager.JoinChannel(channel, false);
+                    channel = channelManager.JoinChannel(channel);
 
                 channelManager.CurrentChannel.Value = channel;
             }
@@ -240,9 +247,15 @@ namespace osu.Game.Overlays
         {
             Channel? newChannel = channel.NewValue;
 
+            // null channel denotes that we should be showing the listing.
             if (newChannel == null)
             {
-                // null channel denotes that we should be showing the listing.
+                currentChannel.Value = channelList.ChannelListingChannel;
+                return;
+            }
+
+            if (newChannel is ChannelListing.ChannelListingChannel)
+            {
                 currentChannelContainer.Clear(false);
                 channelListing.Show();
                 textBar.ShowSearch.Value = true;
@@ -290,9 +303,9 @@ namespace osu.Game.Overlays
             switch (args.Action)
             {
                 case NotifyCollectionChangedAction.Add:
-                    IEnumerable<Channel> joinedChannels = filterChannels(args.NewItems);
+                    IEnumerable<Channel> newChannels = filterChannels(args.NewItems);
 
-                    foreach (var channel in joinedChannels)
+                    foreach (var channel in newChannels)
                         channelList.AddChannel(channel);
 
                     break;