Index: uspace/app/taskbar-cfg/startmenu.c
===================================================================
--- uspace/app/taskbar-cfg/startmenu.c	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/app/taskbar-cfg/startmenu.c	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -54,4 +54,5 @@
 static void startmenu_delete_entry_clicked(ui_pbutton_t *, void *);
 static void startmenu_edit_entry_clicked(ui_pbutton_t *, void *);
+static void startmenu_sep_entry_clicked(ui_pbutton_t *, void *);
 static void startmenu_up_entry_clicked(ui_pbutton_t *, void *);
 static void startmenu_down_entry_clicked(ui_pbutton_t *, void *);
@@ -75,4 +76,9 @@
 ui_pbutton_cb_t startmenu_edit_entry_button_cb = {
 	.clicked = startmenu_edit_entry_clicked
+};
+
+/** Separator entry button callbacks */
+ui_pbutton_cb_t startmenu_sep_entry_button_cb = {
+	.clicked = startmenu_sep_entry_clicked
 };
 
@@ -275,7 +281,7 @@
 	    &startmenu_edit_entry_button_cb, (void *)smenu);
 
-	/* Move entry up button */
-
-	rc = ui_pbutton_create(ui_res, "Up", &smenu->up_entry);
+	/* Separator entry button */
+
+	rc = ui_pbutton_create(ui_res, "Separator", &smenu->sep_entry);
 	if (rc != EOK) {
 		printf("Error creating button.\n");
@@ -285,17 +291,17 @@
 	if (ui_resource_is_textmode(ui_res)) {
 		rect.p0.x = 58;
-		rect.p0.y = 12;
+		rect.p0.y = 11;
 		rect.p1.x = 68;
-		rect.p1.y = 13;
+		rect.p1.y = 12;
 	} else {
 		rect.p0.x = 370;
-		rect.p0.y = 190;
+		rect.p0.y = 170;
 		rect.p1.x = 450;
-		rect.p1.y = 215;
-	}
-
-	ui_pbutton_set_rect(smenu->up_entry, &rect);
-
-	rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->up_entry));
+		rect.p1.y = 195;
+	}
+
+	ui_pbutton_set_rect(smenu->sep_entry, &rect);
+
+	rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->sep_entry));
 	if (rc != EOK) {
 		printf("Error adding control to layout.\n");
@@ -303,10 +309,10 @@
 	}
 
-	ui_pbutton_set_cb(smenu->up_entry,
-	    &startmenu_up_entry_button_cb, (void *)smenu);
-
-	/* Move entry down button */
-
-	rc = ui_pbutton_create(ui_res, "Down", &smenu->down_entry);
+	ui_pbutton_set_cb(smenu->sep_entry,
+	    &startmenu_sep_entry_button_cb, (void *)smenu);
+
+	/* Move entry up button */
+
+	rc = ui_pbutton_create(ui_res, "Up", &smenu->up_entry);
 	if (rc != EOK) {
 		printf("Error creating button.\n");
@@ -316,7 +322,7 @@
 	if (ui_resource_is_textmode(ui_res)) {
 		rect.p0.x = 58;
-		rect.p0.y = 14;
+		rect.p0.y = 13;
 		rect.p1.x = 68;
-		rect.p1.y = 15;
+		rect.p1.y = 14;
 	} else {
 		rect.p0.x = 370;
@@ -324,4 +330,35 @@
 		rect.p1.x = 450;
 		rect.p1.y = 245;
+	}
+
+	ui_pbutton_set_rect(smenu->up_entry, &rect);
+
+	rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->up_entry));
+	if (rc != EOK) {
+		printf("Error adding control to layout.\n");
+		goto error;
+	}
+
+	ui_pbutton_set_cb(smenu->up_entry,
+	    &startmenu_up_entry_button_cb, (void *)smenu);
+
+	/* Move entry down button */
+
+	rc = ui_pbutton_create(ui_res, "Down", &smenu->down_entry);
+	if (rc != EOK) {
+		printf("Error creating button.\n");
+		goto error;
+	}
+
+	if (ui_resource_is_textmode(ui_res)) {
+		rect.p0.x = 58;
+		rect.p0.y = 15;
+		rect.p1.x = 68;
+		rect.p1.y = 16;
+	} else {
+		rect.p0.x = 370;
+		rect.p0.y = 250;
+		rect.p1.x = 450;
+		rect.p1.y = 275;
 	}
 
@@ -418,4 +455,5 @@
 	startmenu_entry_t *smentry;
 	ui_list_entry_attr_t attr;
+	bool separator;
 	errno_t rc;
 
@@ -428,6 +466,12 @@
 
 	ui_list_entry_attr_init(&attr);
-	attr.caption = smenu_entry_get_caption(entry);
+	separator = smenu_entry_get_separator(entry);
+	if (separator)
+		attr.caption = "-- Separator --";
+	else
+		attr.caption = smenu_entry_get_caption(entry);
+
 	attr.arg = (void *)smentry;
+
 	rc = ui_list_entry_append(smenu->entries_list, &attr, &smentry->lentry);
 	if (rc != EOK) {
@@ -473,4 +517,22 @@
 }
 
+/** Create new separator menu entry.
+ *
+ * @param smenu Start menu
+ */
+void startmenu_sep_entry(startmenu_t *smenu)
+{
+	startmenu_entry_t *smentry = NULL;
+	smenu_entry_t *entry;
+	errno_t rc;
+
+	rc = smenu_entry_sep_create(smenu->tbarcfg->tbarcfg, &entry);
+	if (rc != EOK)
+		return;
+
+	(void)startmenu_insert(smenu, entry, &smentry);
+	(void)ui_control_paint(ui_list_ctl(smenu->entries_list));
+}
+
 /** Edit selected menu entry.
  *
@@ -485,4 +547,8 @@
 	smentry = startmenu_get_selected(smenu);
 	if (smentry == NULL)
+		return;
+
+	/* Do not edit separator entries */
+	if (smenu_entry_get_separator(smentry->entry))
 		return;
 
@@ -582,9 +648,22 @@
 }
 
-/** Up entry button clicked.
+/** Separator entry button clicked.
  *
  * @param pbutton Push button
  * @param arg Argument (startmenu_t *)
  */
+static void startmenu_sep_entry_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	startmenu_t *smenu = (startmenu_t *)arg;
+
+	(void)pbutton;
+	startmenu_sep_entry(smenu);
+}
+
+/** Up entry button clicked.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (startmenu_t *)
+ */
 static void startmenu_up_entry_clicked(ui_pbutton_t *pbutton, void *arg)
 {
Index: uspace/app/taskbar-cfg/startmenu.h
===================================================================
--- uspace/app/taskbar-cfg/startmenu.h	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/app/taskbar-cfg/startmenu.h	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2023 Jiri Svoboda
+ * Copyright (c) 2024 Jiri Svoboda
  * All rights reserved.
  *
@@ -48,4 +48,5 @@
 extern startmenu_entry_t *startmenu_get_selected(startmenu_t *);
 extern void startmenu_new_entry(startmenu_t *);
+extern void startmenu_sep_entry(startmenu_t *);
 extern void startmenu_edit(startmenu_t *);
 extern errno_t startmenu_entry_update(startmenu_entry_t *);
Index: uspace/app/taskbar-cfg/types/startmenu.h
===================================================================
--- uspace/app/taskbar-cfg/types/startmenu.h	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/app/taskbar-cfg/types/startmenu.h	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -62,4 +62,6 @@
 	/** Edit entry button */
 	ui_pbutton_t *edit_entry;
+	/** Separator entry button */
+	ui_pbutton_t *sep_entry;
 	/** Move entry up button */
 	ui_pbutton_t *up_entry;
Index: uspace/app/taskbar/tbsmenu.c
===================================================================
--- uspace/app/taskbar/tbsmenu.c	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/app/taskbar/tbsmenu.c	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -129,4 +129,5 @@
 	tbarcfg_t *tbcfg = NULL;
 	smenu_entry_t *sme;
+	bool separator;
 	const char *caption;
 	const char *cmd;
@@ -140,11 +141,19 @@
 	sme = tbarcfg_smenu_first(tbcfg);
 	while (sme != NULL) {
-		caption = smenu_entry_get_caption(sme);
-		cmd = smenu_entry_get_cmd(sme);
-		terminal = smenu_entry_get_terminal(sme);
-
-		rc = tbsmenu_add(tbsmenu, caption, cmd, terminal, &tentry);
-		if (rc != EOK)
-			goto error;
+		separator = smenu_entry_get_separator(sme);
+		if (separator == false) {
+			caption = smenu_entry_get_caption(sme);
+			cmd = smenu_entry_get_cmd(sme);
+			terminal = smenu_entry_get_terminal(sme);
+
+			rc = tbsmenu_add(tbsmenu, caption, cmd, terminal,
+			    &tentry);
+			if (rc != EOK)
+				goto error;
+		} else {
+			rc = tbsmenu_add_sep(tbsmenu, &tentry);
+			if (rc != EOK)
+				goto error;
+		}
 
 		(void)tentry;
@@ -272,4 +281,35 @@
 	if (entry->cmd != NULL)
 		free(entry->cmd);
+	free(entry);
+	return rc;
+}
+
+/** Add separator entry to start menu.
+ *
+ * @param tbsmenu Start menu
+ * @param entry Start menu entry
+ * @return @c EOK on success or an error code
+ */
+errno_t tbsmenu_add_sep(tbsmenu_t *tbsmenu, tbsmenu_entry_t **rentry)
+{
+	errno_t rc;
+	tbsmenu_entry_t *entry;
+
+	entry = calloc(1, sizeof(tbsmenu_entry_t));
+	if (entry == NULL)
+		return ENOMEM;
+
+	rc = ui_menu_entry_sep_create(tbsmenu->smenu, &entry->mentry);
+	if (rc != EOK)
+		goto error;
+
+	ui_menu_entry_set_cb(entry->mentry, tbsmenu_smenu_entry_cb,
+	    (void *)entry);
+
+	entry->tbsmenu = tbsmenu;
+	list_append(&entry->lentries, &tbsmenu->entries);
+	*rentry = entry;
+	return EOK;
+error:
 	free(entry);
 	return rc;
Index: uspace/app/taskbar/tbsmenu.h
===================================================================
--- uspace/app/taskbar/tbsmenu.h	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/app/taskbar/tbsmenu.h	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -55,4 +55,5 @@
 extern errno_t tbsmenu_add(tbsmenu_t *, const char *, const char *, bool,
     tbsmenu_entry_t **);
+extern errno_t tbsmenu_add_sep(tbsmenu_t *, tbsmenu_entry_t **);
 extern void tbsmenu_remove(tbsmenu_t *, tbsmenu_entry_t *, bool);
 extern tbsmenu_entry_t *tbsmenu_first(tbsmenu_t *);
Index: uspace/lib/tbarcfg/include/tbarcfg/tbarcfg.h
===================================================================
--- uspace/lib/tbarcfg/include/tbarcfg/tbarcfg.h	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/lib/tbarcfg/include/tbarcfg/tbarcfg.h	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -52,4 +52,5 @@
 extern const char *smenu_entry_get_cmd(smenu_entry_t *);
 extern bool smenu_entry_get_terminal(smenu_entry_t *);
+extern bool smenu_entry_get_separator(smenu_entry_t *);
 extern errno_t smenu_entry_set_caption(smenu_entry_t *, const char *);
 extern errno_t smenu_entry_set_cmd(smenu_entry_t *, const char *);
@@ -58,4 +59,5 @@
 extern errno_t smenu_entry_create(tbarcfg_t *, const char *, const char *,
     bool, smenu_entry_t **);
+extern errno_t smenu_entry_sep_create(tbarcfg_t *, smenu_entry_t **);
 extern errno_t smenu_entry_destroy(smenu_entry_t *);
 extern errno_t smenu_entry_move_up(smenu_entry_t *);
Index: uspace/lib/tbarcfg/private/tbarcfg.h
===================================================================
--- uspace/lib/tbarcfg/private/tbarcfg.h	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/lib/tbarcfg/private/tbarcfg.h	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -61,4 +61,6 @@
 	/** SIF node (persistent storage) */
 	sif_node_t *nentry;
+	/** Is this a separator entry */
+	bool separator;
 	/** Entry caption (with accelerator markup) */
 	char *caption;
@@ -71,4 +73,5 @@
 extern errno_t smenu_entry_new(tbarcfg_t *, sif_node_t *, const char *,
     const char *, bool, smenu_entry_t **);
+extern errno_t smenu_entry_sep_new(tbarcfg_t *, sif_node_t *, smenu_entry_t **);
 extern void smenu_entry_delete(smenu_entry_t *);
 
Index: uspace/lib/tbarcfg/src/tbarcfg.c
===================================================================
--- uspace/lib/tbarcfg/src/tbarcfg.c	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/lib/tbarcfg/src/tbarcfg.c	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -108,4 +108,5 @@
 	sif_node_t *nentry;
 	const char *ntype;
+	const char *separator;
 	const char *caption;
 	const char *cmd;
@@ -143,24 +144,36 @@
 		}
 
-		caption = sif_node_get_attr(nentry, "caption");
-		if (caption == NULL) {
+		separator = sif_node_get_attr(nentry, "separator");
+		if (separator != NULL && str_cmp(separator, "y") != 0) {
 			rc = EIO;
 			goto error;
 		}
 
-		cmd = sif_node_get_attr(nentry, "cmd");
-		if (cmd == NULL) {
-			rc = EIO;
-			goto error;
+		if (separator == NULL) {
+			caption = sif_node_get_attr(nentry, "caption");
+			if (caption == NULL) {
+				rc = EIO;
+				goto error;
+			}
+
+			cmd = sif_node_get_attr(nentry, "cmd");
+			if (cmd == NULL) {
+				rc = EIO;
+				goto error;
+			}
+
+			terminal = sif_node_get_attr(nentry, "terminal");
+			if (terminal == NULL)
+				terminal = "n";
+
+			rc = smenu_entry_new(tbcfg, nentry, caption, cmd,
+			    str_cmp(terminal, "y") == 0, NULL);
+			if (rc != EOK)
+				goto error;
+		} else {
+			rc = smenu_entry_sep_new(tbcfg, nentry, NULL);
+			if (rc != EOK)
+				goto error;
 		}
-
-		terminal = sif_node_get_attr(nentry, "terminal");
-		if (terminal == NULL)
-			terminal = "n";
-
-		rc = smenu_entry_new(tbcfg, nentry, caption, cmd,
-		    str_cmp(terminal, "y") == 0, NULL);
-		if (rc != EOK)
-			goto error;
 
 		nentry = sif_node_next_child(nentry);
@@ -266,4 +279,5 @@
 const char *smenu_entry_get_caption(smenu_entry_t *entry)
 {
+	assert(!entry->separator);
 	return entry->caption;
 }
@@ -276,8 +290,9 @@
 const char *smenu_entry_get_cmd(smenu_entry_t *entry)
 {
+	assert(!entry->separator);
 	return entry->cmd;
 }
 
-/** Get start menu start in terminal flag.
+/** Get start menu entry start in terminal flag.
  *
  * @param entry Start menu entry
@@ -286,5 +301,16 @@
 bool smenu_entry_get_terminal(smenu_entry_t *entry)
 {
+	assert(!entry->separator);
 	return entry->terminal;
+}
+
+/** Get start menu entry separator flag.
+ *
+ * @param entry Start menu entry
+ * @return Separator flag
+ */
+bool smenu_entry_get_separator(smenu_entry_t *entry)
+{
+	return entry->separator;
 }
 
@@ -301,4 +327,6 @@
 {
 	char *dcap;
+
+	assert(!entry->separator);
 
 	dcap = str_dup(caption);
@@ -324,4 +352,6 @@
 	char *dcmd;
 
+	assert(!entry->separator);
+
 	dcmd = str_dup(cmd);
 	if (dcmd == NULL)
@@ -343,4 +373,5 @@
 void smenu_entry_set_terminal(smenu_entry_t *entry, bool terminal)
 {
+	assert(!entry->separator);
 	entry->terminal = terminal;
 }
@@ -355,16 +386,25 @@
 	errno_t rc;
 
-	rc = sif_node_set_attr(trans, entry->nentry, "cmd", entry->cmd);
-	if (rc != EOK)
-		goto error;
-
-	rc = sif_node_set_attr(trans, entry->nentry, "caption", entry->caption);
-	if (rc != EOK)
-		goto error;
-
-	rc = sif_node_set_attr(trans, entry->nentry, "terminal",
-	    entry->terminal ? "y" : "n");
-	if (rc != EOK)
-		goto error;
+	if (entry->separator) {
+		rc = sif_node_set_attr(trans, entry->nentry, "separator", "y");
+		if (rc != EOK)
+			goto error;
+	} else {
+		sif_node_unset_attr(trans, entry->nentry, "separator");
+
+		rc = sif_node_set_attr(trans, entry->nentry, "cmd", entry->cmd);
+		if (rc != EOK)
+			goto error;
+
+		rc = sif_node_set_attr(trans, entry->nentry, "caption",
+		    entry->caption);
+		if (rc != EOK)
+			goto error;
+
+		rc = sif_node_set_attr(trans, entry->nentry, "terminal",
+		    entry->terminal ? "y" : "n");
+		if (rc != EOK)
+			goto error;
+	}
 
 	return EOK;
@@ -457,4 +497,38 @@
 }
 
+/** Allocate a start menu separator entry and append it to the start menu
+ * (internal).
+ *
+ * This only creates the entry in memory, but does not update the repository.
+ *
+ * @param smenu Start menu
+ * @param nentry Backing SIF node
+ * @param rentry Place to store pointer to new entry or @c NULL
+ */
+errno_t smenu_entry_sep_new(tbarcfg_t *smenu, sif_node_t *nentry,
+    smenu_entry_t **rentry)
+{
+	smenu_entry_t *entry;
+	errno_t rc;
+
+	entry = calloc(1, sizeof(smenu_entry_t));
+	if (entry == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	entry->nentry = nentry;
+	entry->separator = true;
+
+	entry->smenu = smenu;
+	list_append(&entry->lentries, &smenu->entries);
+	if (rentry != NULL)
+		*rentry = entry;
+
+	return EOK;
+error:
+	return rc;
+}
+
 /** Delete start menu entry.
  *
@@ -467,6 +541,8 @@
 {
 	list_remove(&entry->lentries);
-	free(entry->caption);
-	free(entry->cmd);
+	if (entry->caption != NULL)
+		free(entry->caption);
+	if (entry->cmd != NULL)
+		free(entry->cmd);
 	free(entry);
 }
@@ -527,4 +603,47 @@
 }
 
+/** Create new start menu separator entry.
+ *
+ * @param smenu Start menu
+ * @param nentry Backing SIF node
+ * @param rentry Place to store pointer to new entry or @c NULL
+ */
+errno_t smenu_entry_sep_create(tbarcfg_t *smenu, smenu_entry_t **rentry)
+{
+	sif_node_t *nentry;
+	smenu_entry_t *entry;
+	errno_t rc;
+	sif_trans_t *trans = NULL;
+
+	rc = sif_trans_begin(smenu->repo, &trans);
+	if (rc != EOK)
+		goto error;
+
+	rc = sif_node_append_child(trans, smenu->nentries, "entry",
+	    &nentry);
+	if (rc != EOK)
+		goto error;
+
+	rc = sif_node_set_attr(trans, nentry, "separator", "y");
+	if (rc != EOK)
+		goto error;
+
+	rc = smenu_entry_sep_new(smenu, nentry, &entry);
+	if (rc != EOK)
+		goto error;
+
+	rc = sif_trans_end(trans);
+	if (rc != EOK)
+		goto error;
+
+	if (rentry != NULL)
+		*rentry = entry;
+	return EOK;
+error:
+	if (trans != NULL)
+		sif_trans_abort(trans);
+	return rc;
+}
+
 /** Destroy start menu entry.
  *
Index: uspace/lib/tbarcfg/test/tbarcfg.c
===================================================================
--- uspace/lib/tbarcfg/test/tbarcfg.c	(revision 5f3188b820d64bcf193dac312a8069c4e69233ee)
+++ uspace/lib/tbarcfg/test/tbarcfg.c	(revision e63e74a596d3dab316c056385061a0ffc336c62b)
@@ -135,4 +135,58 @@
 }
 
+/** Separator entry */
+PCUT_TEST(separator)
+{
+	errno_t rc;
+	tbarcfg_t *tbcfg;
+	char fname[L_tmpnam], *p;
+	const char *caption;
+	const char *cmd;
+	smenu_entry_t *e1 = NULL, *e2 = NULL;
+	smenu_entry_t *e;
+
+	p = tmpnam(fname);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	rc = tbarcfg_create(fname, &tbcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = smenu_entry_create(tbcfg, "A", "a", false, &e1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(e1);
+
+	rc = smenu_entry_sep_create(tbcfg, &e2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(e2);
+
+	PCUT_ASSERT_FALSE(smenu_entry_get_separator(e1));
+	PCUT_ASSERT_TRUE(smenu_entry_get_separator(e2));
+
+	tbarcfg_close(tbcfg);
+
+	/* Re-open repository */
+
+	rc = tbarcfg_open(fname, &tbcfg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	e = tbarcfg_smenu_first(tbcfg);
+	PCUT_ASSERT_NOT_NULL(e);
+
+	/* Check that new values of properties have persisted */
+	PCUT_ASSERT_FALSE(smenu_entry_get_separator(e));
+	caption = smenu_entry_get_caption(e);
+	PCUT_ASSERT_STR_EQUALS("A", caption);
+	cmd = smenu_entry_get_cmd(e);
+	PCUT_ASSERT_STR_EQUALS("a", cmd);
+
+	e = tbarcfg_smenu_next(e);
+
+	/* Check that entry is still a separator */
+	PCUT_ASSERT_TRUE(smenu_entry_get_separator(e));
+
+	tbarcfg_close(tbcfg);
+	remove(fname);
+}
+
 /** Getting menu entry properties */
 PCUT_TEST(get_caption_cmd_term)
