diff --git a/scribus/CMakeLists.txt b/scribus/CMakeLists.txt
index 33c757c1581ca747cb9ec97c6cf2ef38302cac92..d4c6ace2b3e2a42e36e09d8e76755a9939639a16 100644
--- a/scribus/CMakeLists.txt
+++ b/scribus/CMakeLists.txt
@@ -34,6 +34,7 @@ add_subdirectory(dtd)
 add_subdirectory(colormgmt)
 add_subdirectory(desaxe)
 add_subdirectory(fonts)
+add_subdirectory(marks)
 add_subdirectory(styles)
 add_subdirectory(text)
 add_subdirectory(ui/qml)
@@ -1127,6 +1128,7 @@ link_directories(
 	${CMAKE_CURRENT_BINARY_DIR}/colormgmt
 	${CMAKE_CURRENT_BINARY_DIR}/desaxe
 	${CMAKE_CURRENT_BINARY_DIR}/fonts
+	${CMAKE_CURRENT_BINARY_DIR}/marks
 	${CMAKE_CURRENT_BINARY_DIR}/styles
 	${CMAKE_CURRENT_BINARY_DIR}/text
 	${CMAKE_CURRENT_BINARY_DIR}/third_party/wpg
@@ -1156,6 +1158,7 @@ if(WITH_TESTS)
 else()
 	set(SCRIBUS_TESTS_LIB "")
 endif()
+set(SCRIBUS_MARKS_LIB "scribus_marks_lib")
 set(SCRIBUS_STYLES_LIB "scribus_styles_lib")
 set(SCRIBUS_FONTS_LIB "scribus_fonts_lib")
 set(SCRIBUS_DESAXE_LIB "scribus_desaxe_lib")
@@ -1225,6 +1228,7 @@ if(HAVE_OSG)
 		${SCRIBUS_MAIN_CPP}
 		${SCRIBUS_UI_SOURCES}
 		${SCRIBUS_TEXT_SOURCES}
+		${SCRIBUS_MARKS_SOURCES}
 		${SCRIBUS_STYLES_SOURCES}
 		${SCRIBUS_COLORMGMT_SOURCES}
 		${SCRIBUS_FONTS_SOURCES}
@@ -1240,6 +1244,7 @@ else()
 		${SCRIBUS_MAIN_CPP}
 		${SCRIBUS_UI_SOURCES}
 		${SCRIBUS_TEXT_SOURCES}
+		${SCRIBUS_MARKS_SOURCES}
 		${SCRIBUS_STYLES_SOURCES}
 		${SCRIBUS_COLORMGMT_SOURCES}
 		${SCRIBUS_FONTS_SOURCES}
@@ -1356,6 +1361,7 @@ target_link_libraries(${EXE_NAME}
 	${SCRIBUS_COLORMGMT_LIB}
 	${SCRIBUS_DESAXE_LIB}
 	${SCRIBUS_TEXT_LIB}
+	${SCRIBUS_MARKS_LIB}
 	${SCRIBUS_STYLES_LIB}
 	${SCRIBUS_FONTS_LIB}
 	${SCRIBUS_WPG_LIB}
diff --git a/scribus/actionmanager.cpp b/scribus/actionmanager.cpp
index 13328224ada0795d77f972e61a9dc9b0bda7bb36..bad1a36bbfa4728730bc944d0dcceb82baf1a6ab 100644
--- a/scribus/actionmanager.cpp
+++ b/scribus/actionmanager.cpp
@@ -31,6 +31,8 @@ for which a new license (GPL+exception) is in place.
 #include "urllauncher.h"
 #include "iconmanager.h"
 
+#include "marks/anchor.h"
+
 QMap<QString, QKeySequence> ActionManager::defKeys;
 QVector< QPair<QString, QStringList> > ActionManager::defMenuNames;
 QVector< QPair<QString, QStringList> > ActionManager::defMenus;
@@ -582,7 +584,7 @@ void ActionManager::initInsertMenuActions()
 	connect( (*scrActions)["insertSampleText"], SIGNAL(triggered()), mainWindow, SLOT(insertSampleText()) );
 	connect( (*scrActions)["stickyTools"], SIGNAL(triggered()), mainWindow, SLOT(ToggleStickyTools()) );
 
-	connect( (*scrActions)["insertMarkAnchor"], SIGNAL(triggered()), mainWindow, SLOT(slotInsertMarkAnchor()) );
+	connect((*scrActions)["insertMarkAnchor"], &ScrAction::triggered, [](){ Marks::Anchor::insertSlot(); });
 	connect( (*scrActions)["insertMarkVariableText"], SIGNAL(triggered()), mainWindow, SLOT(slotInsertMarkVariableText()) );
 	connect( (*scrActions)["insertMarkItem"], SIGNAL(triggered()), mainWindow, SLOT(slotInsertMarkItem()) );
 	connect( (*scrActions)["insertMark2Mark"], SIGNAL(triggered()), mainWindow, SLOT(slotInsertMark2Mark()) );
diff --git a/scribus/marks/CMakeLists.txt b/scribus/marks/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ebf06a1f91a7ee7803e725d89ed646e5cdb4b25a
--- /dev/null
+++ b/scribus/marks/CMakeLists.txt
@@ -0,0 +1,36 @@
+include_directories(
+	${CMAKE_SOURCE_DIR}
+	${CMAKE_SOURCE_DIR}/scribus
+	${FREETYPE_INCLUDE_DIRS}
+)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_FPIC}")
+
+set(SCRIBUS_MARKS_MOC_CLASSES
+	anchor.h
+	anchordialog.h
+)
+
+set(SCRIBUS_MARKS_UI_SRC
+	anchordialog.ui
+)
+
+set(SCRIBUS_MARKS_LIB_SOURCES
+	marks.cpp
+	anchor.cpp
+	anchordialog.cpp
+)
+
+QT5_WRAP_CPP(SCRIBUS_MARKS_MOC_SOURCES ${SCRIBUS_MARKS_MOC_CLASSES})
+QT5_WRAP_UI(SCRIBUS_MARKS_UI_SOURCES ${SCRIBUS_MARKS_UI_SRC})
+
+set(SCRIBUS_MARKS_LIB "scribus_marks_lib")
+add_library(${SCRIBUS_MARKS_LIB} STATIC ${SCRIBUS_MARKS_LIB_SOURCES} ${SCRIBUS_MARKS_MOC_SOURCES} ${SCRIBUS_MARKS_UI_SOURCES})
+
+# This is a convenience library that for linkage purposes is part of Scribus's
+# main API.
+set_target_properties(${SCRIBUS_MARKS_LIB}
+	PROPERTIES
+	COMPILE_FLAGS -DCOMPILE_SCRIBUS_MAIN_APP
+)
+
diff --git a/scribus/marks/anchor.cpp b/scribus/marks/anchor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f7223e01ac9a8bc3fb027b277163075590620c4
--- /dev/null
+++ b/scribus/marks/anchor.cpp
@@ -0,0 +1,80 @@
+#include "marks/anchor.h"
+
+#include "scribuscore.h"
+#include "scribus.h"
+#include "scribusdoc.h"
+#include "undomanager.h"
+#include "pageitem_textframe.h"
+#include "util.h"
+
+#include "marks/marks.h"
+#include "marks/anchordialog.h"
+
+namespace Marks {
+
+bool Anchor::insert(PageItem_TextFrame* textFrame, QString& label)
+{
+	auto doc = textFrame->doc();
+	auto undoManager = UndoManager::instance();
+
+	// there cannot be bookmarks on master pages
+	if (doc->masterPageMode())
+		return false;
+
+	auto trans = undoManager->beginTransaction();
+	// TODO: if there is a selection use it as the label, do not delete it
+	if (textFrame->HasSel)
+	{
+		trans = undoManager->beginTransaction(Um::Selection, Um::IDelete, Um::Delete, QString(), Um::IDelete);
+		textFrame->deleteSelectedTextFromFrame();
+	}
+
+	MarkData markdata;
+	markdata.itemName = textFrame->itemName();
+	markdata.itemPtr = textFrame;
+
+	Mark* mrk = doc->newMark();
+	mrk->setValues(label, textFrame->OwnPage, MARKAnchorType, markdata);
+	// TODO: remove selection, insert mark, restore the selection
+	textFrame->itemText.insertMark(mrk);
+	mrk->OwnPage = textFrame->OwnPage;
+
+	if (undoManager->undoEnabled())
+	{
+		ScItemsState* is = new ScItemsState(undoManager->InsertMark);
+		is->set("ETEA", mrk->label);
+		is->set("label", mrk->label);
+		is->set("type", (int) mrk->getType());
+		is->set("MARK", QString("new"));
+		is->set("strtxt", mrk->getString());
+		is->set("at", textFrame->itemText.cursorPosition() -1);
+		is->insertItem("inItem", textFrame);
+		undoManager->action(doc, is);
+
+		trans.commit();
+	}
+	return true;
+}
+
+void Anchor::insertSlot()
+{
+	auto win = ScCore->primaryMainWindow();
+	if  (!win->HaveDoc)
+		return;
+
+	auto currItem = Marks::getTextFrameFromPage(win->doc);
+	if (!currItem)
+		return;
+
+	AnchorDialog dialog(win);
+	if (!dialog.exec())
+		return;
+
+	QString label = dialog.getLabel();
+	getUniqueName(label, win->doc->marksLabelsList(MARKAnchorType), "_");
+
+	if (insert(currItem, label))
+		Marks::refreshView(currItem);
+}
+
+}
diff --git a/scribus/marks/anchor.h b/scribus/marks/anchor.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6709fb8da79ba4b735ea7875a0ce21bf3ab0edb
--- /dev/null
+++ b/scribus/marks/anchor.h
@@ -0,0 +1,29 @@
+#ifndef MARKSANCHOR_H
+#define MARKSANCHOR_H
+
+#include <QObject>
+#include <QString>
+#include "scribusapi.h"
+
+class PageItem_TextFrame;
+
+namespace Marks {
+
+class SCRIBUS_API Anchor : public QObject
+{
+    Q_OBJECT
+
+private:
+	Anchor() = default;
+	~Anchor() = default;
+
+public:
+	/** \return true if the mark was insterted */
+	static bool insert(PageItem_TextFrame* pageItem, QString& label);
+public slots:
+	static void insertSlot();
+};
+
+}
+
+#endif // MARKSANCHOR_H
diff --git a/scribus/marks/anchordialog.cpp b/scribus/marks/anchordialog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c418ca2c97cc7e077d368148d469aa2d84050eb9
--- /dev/null
+++ b/scribus/marks/anchordialog.cpp
@@ -0,0 +1,29 @@
+#include "marks/anchordialog.h"
+#include "marks/marks.h"
+
+namespace Marks {
+
+AnchorDialog::AnchorDialog(QWidget *parent) :
+	QDialog(parent),
+	ui{new Ui::AnchorDialog}
+{
+	ui->setupUi(this);
+}
+
+AnchorDialog::~AnchorDialog()
+{
+	delete ui;
+}
+
+QString AnchorDialog::getLabel()
+{
+	auto label = ui->labelEdit->text();
+	return label.isEmpty() ? tr("Anchor mark") : label;
+}
+
+void AnchorDialog::setLabel(const QString& label)
+{
+	ui->labelEdit->setText(label);
+}
+
+}
diff --git a/scribus/marks/anchordialog.h b/scribus/marks/anchordialog.h
new file mode 100644
index 0000000000000000000000000000000000000000..7558f30fd0b5433d4a63710a8c4bbf9e999f58a1
--- /dev/null
+++ b/scribus/marks/anchordialog.h
@@ -0,0 +1,31 @@
+#ifndef MARKSANCHORDIALOG_H
+#define MARKSANCHORDIALOG_H
+
+#include <QDialog>
+#include "scribusapi.h"
+#include "marks/ui_anchordialog.h"
+
+
+namespace Marks {
+
+namespace Ui { class AnchorDialog; }
+
+
+class SCRIBUS_API AnchorDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+	AnchorDialog(QWidget *parent = nullptr);
+	~AnchorDialog();
+
+	QString getLabel();
+	void setLabel(const QString& label);
+
+private:
+	Ui::AnchorDialog *ui;
+};
+
+}
+
+#endif // MARKSANCHORDIALOG_H
diff --git a/scribus/marks/anchordialog.ui b/scribus/marks/anchordialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..4913b08bb3035ef1fad3f753fa6a73dcaceaf6b2
--- /dev/null
+++ b/scribus/marks/anchordialog.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Marks::AnchorDialog</class>
+ <widget class="QDialog" name="Marks::AnchorDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>81</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>0</width>
+    <height>81</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>81</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Insert new Anchor</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Label:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLineEdit" name="labelEdit"/>
+   </item>
+   <item row="1" column="1">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>Marks::AnchorDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>Marks::AnchorDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/scribus/marks/marks.cpp b/scribus/marks/marks.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..de35775c3cde39903f378ade0f48bba65f54b46e
--- /dev/null
+++ b/scribus/marks/marks.cpp
@@ -0,0 +1,45 @@
+#include "marks.h"
+
+#include "scribuscore.h"
+#include "scribus.h"
+#include "scribusdoc.h"
+#include "pageitem.h"
+#include "pageitem_textframe.h"
+#include "selection.h"
+#include "scribusview.h"
+
+namespace Marks {
+
+PageItem_TextFrame* Marks::getTextFrame(ScribusDoc* doc)
+{
+	if (doc->m_Selection->count() != 1)
+		return nullptr;
+	if  (doc->appMode != modeEdit)
+		return nullptr;
+	auto currItem = doc->m_Selection->itemAt(0);
+	if (!currItem->isTextFrame())
+		return nullptr;
+	return currItem->asTextFrame();
+}
+
+PageItem_TextFrame* Marks::getTextFrameFromPage(ScribusDoc* doc)
+{
+	if (doc->masterPageMode())
+		return nullptr;
+	return getTextFrame(doc);
+}
+
+void Marks::refreshView(PageItem_TextFrame* textFrame)
+{
+	auto doc = textFrame->doc();
+	auto view = ScCore->primaryMainWindow()->view;
+
+	view->updatesOn(false);
+	textFrame->invalidateLayout();
+	textFrame->layout();
+	doc->changed();
+	view->updatesOn(true);
+	view->DrawNew();
+}
+
+}
diff --git a/scribus/marks/marks.h b/scribus/marks/marks.h
new file mode 100644
index 0000000000000000000000000000000000000000..020c7561713dc5c39340586fff88add918cae006
--- /dev/null
+++ b/scribus/marks/marks.h
@@ -0,0 +1,22 @@
+#ifndef MARKSMARKS_H
+#define MARKSMARKS_H
+
+class PageItem_TextFrame;
+class ScribusDoc;
+
+namespace Marks {
+
+class Marks
+{
+public:
+	/** @brief return the currently selected text frame on the page or master page*/
+	static PageItem_TextFrame* getTextFrame(ScribusDoc* doc);
+	/** @brief return the currently selected text frame on the page */
+	static PageItem_TextFrame* getTextFrameFromPage(ScribusDoc* doc);
+	/** @brief refresh the layout */
+	static void refreshView(PageItem_TextFrame* textFrame);
+};
+
+}
+
+#endif // Marks
diff --git a/scribus/scribus.h b/scribus/scribus.h
index 71cee3f2ba1c243606c81840f09d78a74dfaf8cc..45c90bbd16c43a2100df6007b1fe70689baa7c89 100644
--- a/scribus/scribus.h
+++ b/scribus/scribus.h
@@ -565,7 +565,6 @@ public slots:
 
 	//inserting marks
 	void slotInsertMark2Mark() { insertMark(MARK2MarkType); }
-	void slotInsertMarkAnchor() { insertMark(MARKAnchorType); }
 	void slotInsertMarkVariableText() { insertMark(MARKVariableTextType); }
 	void slotInsertMarkItem() { insertMark(MARK2ItemType); }
 	void slotInsertMarkNote();
