diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt
new file mode 100644
index 0000000000000000000000000000000000000000..26511da0f91cd29d2cd0fde54df6fb1dcec73ec3
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/AddForumDialog.kt
@@ -0,0 +1,165 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.briarproject.briar.desktop.forums
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.Button
+import androidx.compose.material.ButtonDefaults
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.OutlinedTextField
+import androidx.compose.material.Scaffold
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.material.TextButton
+import androidx.compose.material.rememberScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Alignment.Companion.CenterEnd
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import androidx.compose.ui.window.WindowPosition
+import androidx.compose.ui.window.rememberDialogState
+import org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH
+import org.briarproject.briar.desktop.utils.AccessibilityUtils.description
+import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
+import org.briarproject.briar.desktop.utils.PreviewUtils
+import java.awt.Dimension
+
+fun main() = PreviewUtils.preview {
+    val visible = mutableStateOf(true)
+    AddForumDialog(visible, {}, { visible.value = false })
+}
+
+@Composable
+fun AddForumDialog(
+    visible: State<Boolean>,
+    onCreate: (String) -> Unit,
+    onCancelButtonClicked: () -> Unit,
+) {
+    Dialog(
+        title = i18n("forum.add.title"),
+        onCloseRequest = onCancelButtonClicked,
+        state = rememberDialogState(
+            position = WindowPosition(Alignment.Center),
+        ),
+        visible = visible.value,
+    ) {
+        window.minimumSize = Dimension(360, 180)
+        val scaffoldState = rememberScaffoldState()
+        val name = rememberSaveable { mutableStateOf("") }
+        Surface {
+            Scaffold(
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .padding(top = 24.dp, bottom = 12.dp),
+                scaffoldState = scaffoldState,
+                topBar = {
+                    Box(Modifier.fillMaxWidth()) {
+                        Text(
+                            text = i18n("forum.add.title"),
+                            style = MaterialTheme.typography.h6,
+                            modifier = Modifier.padding(bottom = 12.dp)
+                        )
+                    }
+                },
+                content = {
+                    AddForumContent(name, onCreate)
+                },
+                bottomBar = {
+                    OkCancelBottomBar(
+                        okButtonLabel = i18n("forum.add.button"),
+                        okButtonEnabled = isValidForumName(name.value),
+                        onOkButtonClicked = {
+                            onCreate(name.value)
+                            name.value = ""
+                        },
+                        onCancelButtonClicked = onCancelButtonClicked,
+                    )
+                },
+            )
+        }
+    }
+}
+
+private fun isValidForumName(name: String): Boolean {
+    return name.isNotBlank() && name.length <= MAX_FORUM_NAME_LENGTH
+}
+
+@Composable
+fun AddForumContent(name: MutableState<String>, onCreate: (String) -> Unit) {
+    val focusRequester = remember { FocusRequester() }
+    OutlinedTextField(
+        value = name.value,
+        onValueChange = { if (it.length <= MAX_FORUM_NAME_LENGTH) name.value = it },
+        label = { Text(i18n("forum.add.hint")) },
+        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
+        singleLine = true,
+        onEnter = {
+            onCreate(name.value)
+            name.value = ""
+        },
+        modifier = Modifier
+            .fillMaxWidth()
+            .focusRequester(focusRequester)
+            .description(i18n("forum.add.hint")),
+    )
+    LaunchedEffect(Unit) {
+        focusRequester.requestFocus()
+    }
+}
+
+@Composable
+fun OkCancelBottomBar(
+    okButtonLabel: String,
+    okButtonEnabled: Boolean = true,
+    onOkButtonClicked: () -> Unit,
+    onCancelButtonClicked: () -> Unit,
+) {
+    Box(Modifier.fillMaxWidth()) {
+        Row(Modifier.align(CenterEnd)) {
+            TextButton(
+                onClick = onCancelButtonClicked,
+                colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error)
+            ) {
+                Text(i18n("cancel"))
+            }
+            Button(
+                onClick = onOkButtonClicked,
+                enabled = okButtonEnabled,
+                modifier = Modifier.padding(start = 8.dp)
+            ) {
+                Text(okButtonLabel)
+            }
+        }
+    }
+}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt
index 2bb44a4f1b975aeb63abc50f965c1501585a1298..b65d5ae6ddfba25475e4fcb9ae7d69e8d413af6e 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsScreen.kt
@@ -25,6 +25,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.AddComment
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import org.briarproject.briar.desktop.conversation.Explainer
@@ -38,8 +40,18 @@ import org.briarproject.briar.desktop.viewmodel.viewModel
 fun ForumsScreen(
     viewModel: ForumsViewModel = viewModel(),
 ) {
+    val addDialogVisible = remember { mutableStateOf(false) }
+    AddForumDialog(
+        visible = addDialogVisible,
+        onCreate = { name ->
+            viewModel.createForum(name)
+            addDialogVisible.value = false
+        },
+        onCancelButtonClicked = { addDialogVisible.value = false }
+    )
+
     if (viewModel.groupList.value.isEmpty()) {
-        NoForumsYet {}
+        NoForumsYet { addDialogVisible.value = true }
     } else {
         Row(modifier = Modifier.fillMaxWidth()) {
             ForumsList(
@@ -48,7 +60,7 @@ fun ForumsScreen(
                 filterBy = viewModel.filterBy,
                 onFilterSet = viewModel::setFilterBy,
                 onGroupIdSelected = viewModel::selectGroup,
-                onAddButtonClicked = {},
+                onAddButtonClicked = { addDialogVisible.value = true },
             )
             VerticalDivider()
             Column(modifier = Modifier.weight(1f).fillMaxHeight()) {
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt
index b92f33acdbf46732c515a1a01e6af62cacd17b8b..245b4481ac81f2c55e1e9c9cb4fd198dcc37a625 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/ForumsViewModel.kt
@@ -27,6 +27,7 @@ import org.briarproject.bramble.api.event.Event
 import org.briarproject.bramble.api.event.EventBus
 import org.briarproject.bramble.api.lifecycle.LifecycleManager
 import org.briarproject.bramble.api.sync.GroupId
+import org.briarproject.bramble.api.sync.event.GroupAddedEvent
 import org.briarproject.briar.api.forum.ForumManager
 import org.briarproject.briar.desktop.threading.BriarExecutors
 import org.briarproject.briar.desktop.utils.clearAndAddAll
@@ -64,7 +65,13 @@ constructor(
     }
 
     override fun eventOccurred(e: Event) {
-        // TODO
+        if (e is GroupAddedEvent) {
+            if (e.group.clientId == ForumManager.CLIENT_ID) loadGroups()
+        }
+    }
+
+    fun createForum(name: String) {
+        forumManager.addForum(name)
     }
 
     private fun loadGroups() {
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt
index 67cc50172827d0d336bb5bf966dcd44ae10898fe..b78786075c7abced04706fbc55517461be46750e 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/forums/GroupsCard.kt
@@ -107,13 +107,19 @@ fun GroupsCard(
                     modifier = Modifier.fillMaxWidth()
                 ) {
                     Text(
-                        text = i18nP("group.card.posts", item.msgCount),
-                        style = MaterialTheme.typography.caption
-                    )
-                    Text(
-                        text = getFormattedTimestamp(item.timestamp),
+                        text = if (item.msgCount > 0) {
+                            i18nP("group.card.posts", item.msgCount)
+                        } else {
+                            i18nP("group.card.no_posts", item.msgCount)
+                        },
                         style = MaterialTheme.typography.caption
                     )
+                    if (item.msgCount > 0) {
+                        Text(
+                            text = getFormattedTimestamp(item.timestamp),
+                            style = MaterialTheme.typography.caption
+                        )
+                    }
                 }
             }
         }
diff --git a/briar-desktop/src/main/resources/strings/BriarDesktop.properties b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
index 1ffc70901b0f2defbc2419319acb3b2c744b2290..eb07b780637d95ada98ffe8aa121dfffdabb893e 100644
--- a/briar-desktop/src/main/resources/strings/BriarDesktop.properties
+++ b/briar-desktop/src/main/resources/strings/BriarDesktop.properties
@@ -106,6 +106,10 @@ forum.search.title=Forums
 forum.empty_state.text=You don't have any forums yet. Tap the + icon to add a forum:
 forum.none_selected.title=No forum selected
 forum.none_selected.hint=Select a forum to start chatting
+forum.add.title=Create Forum
+forum.add.hint=Choose a name for your forum
+forum.add.button=Create forum
+group.card.no_posts=No posts
 group.card.posts={0, plural, one {{0} post} other {{0} posts}}
 
 # Private Groups