diff --git a/arho_feature_template/gui/new_plan_regulation_group_form.py b/arho_feature_template/gui/new_plan_regulation_group_form.py
new file mode 100644
index 0000000..fb2c223
--- /dev/null
+++ b/arho_feature_template/gui/new_plan_regulation_group_form.py
@@ -0,0 +1,70 @@
+from __future__ import annotations
+
+from importlib import resources
+from typing import TYPE_CHECKING
+
+from qgis.PyQt import uic
+from qgis.PyQt.QtWidgets import QDialog, QTreeWidget, QTreeWidgetItem
+
+from arho_feature_template.gui.new_plan_regulation_widget import NewPlanRegulationWidget
+
+if TYPE_CHECKING:
+    from qgis.PyQt.QtWidgets import QBoxLayout, QWidget
+
+ui_path = resources.files(__package__) / "new_plan_regulation_group_form.ui"
+FormClass, _ = uic.loadUiType(ui_path)
+
+
+class NewPlanRegulationGroupForm(QDialog, FormClass):  # type: ignore
+    """Form to create a new plan regulation group."""
+
+    def __init__(self):
+        super().__init__()
+        self.setupUi(self)
+
+        # TYPES
+        self.plan_regulations_view: QTreeWidget
+        self.plan_regulations_scroll_area_contents: QWidget
+        self.plan_regulations_layout: QBoxLayout
+
+        # INIT
+        self.initialize_plan_regulations()
+        self.plan_regulations_view.itemDoubleClicked.connect(self.add_selected_plan_regulation)
+
+    def initialize_plan_regulations(self):
+        # NOTE: Replace the dummy plan regulation codes below with codes from DB
+        plan_regulation_codes = {
+            "category 1": ["regulation 1", "regulation 2"],
+            "category 2": ["regulation 3"],
+            "category 3": ["regulation 4", "regulation 5", "regulation 6"],
+        }
+
+        # Initialize categories
+        for category_name, plan_regulations in plan_regulation_codes.items():
+            category_item = QTreeWidgetItem()
+            category_item.setText(0, category_name)
+            self.plan_regulations_view.addTopLevelItem(category_item)
+
+            # Initialize plan regulations under the categories
+            for plan_regulation_type in plan_regulations:
+                plan_regulation_item = QTreeWidgetItem(category_item)
+                plan_regulation_item.setText(0, plan_regulation_type)
+                self.plan_regulations_view.addTopLevelItem(plan_regulation_item)
+
+    def add_selected_plan_regulation(self, item: QTreeWidgetItem, column: int):
+        # If user double clicked category, don't add plan regulation
+        if not item.parent():
+            return
+        self.add_plan_regulation(item.text(column))
+
+    def add_plan_regulation(self, regulation_type: str):
+        new_plan_regulation_widget = NewPlanRegulationWidget(
+            regulation_type=regulation_type, parent=self.plan_regulations_scroll_area_contents
+        )
+        new_plan_regulation_widget.delete_signal.connect(self.delete_plan_regulation)
+        index = self.plan_regulations_layout.count() - 1
+        self.plan_regulations_layout.insertWidget(index, new_plan_regulation_widget)
+
+    def delete_plan_regulation(self, plan_regulation_widget: NewPlanRegulationWidget):
+        self.plan_regulations_layout.removeWidget(plan_regulation_widget)
+        plan_regulation_widget.deleteLater()
diff --git a/arho_feature_template/gui/new_plan_regulation_group_form.ui b/arho_feature_template/gui/new_plan_regulation_group_form.ui
new file mode 100644
index 0000000..7fff8e6
--- /dev/null
+++ b/arho_feature_template/gui/new_plan_regulation_group_form.ui
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>769</width>
+    <height>535</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Luo kaavamääräysryhmä</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QTabWidget" name="tabs">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="plan_regulation_group_info_tab">
+      <attribute name="title">
+       <string>Kaavamääräysryhmän tiedot</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_3">
+       <item>
+        <widget class="QScrollArea" name="scrollArea">
+         <property name="widgetResizable">
+          <bool>true</bool>
+         </property>
+         <widget class="QWidget" name="scrollAreaWidgetContents">
+          <property name="geometry">
+           <rect>
+            <x>0</x>
+            <y>0</y>
+            <width>727</width>
+            <height>435</height>
+           </rect>
+          </property>
+          <layout class="QFormLayout" name="formLayout">
+           <item row="0" column="0">
+            <widget class="QLabel" name="label_2">
+             <property name="text">
+              <string>Kaavamääräyksen otsikko</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QLineEdit" name="heading"/>
+           </item>
+           <item row="1" column="0">
+            <widget class="QLabel" name="label_3">
+             <property name="text">
+              <string>Kirjaintunnus</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QLineEdit" name="code"/>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="label">
+             <property name="text">
+              <string>Ryhmänumero</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="group_number"/>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="label_5">
+             <property name="text">
+              <string>Värikoodi</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="color_code"/>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="plan_regulations_tab">
+      <attribute name="title">
+       <string>Kaavamääräykset</string>
+      </attribute>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QTreeWidget" name="plan_regulations_view">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Maximum" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <attribute name="headerVisible">
+          <bool>false</bool>
+         </attribute>
+         <column>
+          <property name="text">
+           <string notr="true">1</string>
+          </property>
+         </column>
+        </widget>
+       </item>
+       <item>
+        <widget class="QScrollArea" name="plan_regulations_scroll_area">
+         <property name="widgetResizable">
+          <bool>true</bool>
+         </property>
+         <widget class="QWidget" name="plan_regulations_scroll_area_contents">
+          <property name="geometry">
+           <rect>
+            <x>0</x>
+            <y>0</y>
+            <width>98</width>
+            <height>28</height>
+           </rect>
+          </property>
+          <layout class="QVBoxLayout" name="plan_regulations_layout">
+           <item>
+            <spacer name="verticalSpacer">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>574</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="recommendations_tab">
+      <attribute name="title">
+       <string>Suositukset</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <item>
+        <widget class="QScrollArea" name="scrollArea_2">
+         <property name="widgetResizable">
+          <bool>true</bool>
+         </property>
+         <widget class="QWidget" name="scrollAreaWidgetContents_2">
+          <property name="geometry">
+           <rect>
+            <x>0</x>
+            <y>0</y>
+            <width>98</width>
+            <height>28</height>
+           </rect>
+          </property>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="button_box">
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>button_box</sender>
+   <signal>rejected()</signal>
+   <receiver>Dialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>384</x>
+     <y>513</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>384</x>
+     <y>267</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/arho_feature_template/gui/new_plan_regulation_widget.py b/arho_feature_template/gui/new_plan_regulation_widget.py
new file mode 100644
index 0000000..74a8df8
--- /dev/null
+++ b/arho_feature_template/gui/new_plan_regulation_widget.py
@@ -0,0 +1,124 @@
+from __future__ import annotations
+
+from enum import Enum
+from importlib import resources
+from typing import TYPE_CHECKING
+
+from qgis.core import QgsApplication
+from qgis.gui import QgsDoubleSpinBox, QgsFileWidget, QgsSpinBox
+from qgis.PyQt import uic
+from qgis.PyQt.QtCore import pyqtSignal
+from qgis.PyQt.QtWidgets import QComboBox, QFormLayout, QHBoxLayout, QLineEdit, QMenu, QSizePolicy, QTextEdit, QWidget
+
+if TYPE_CHECKING:
+    from qgis.PyQt.QtWidgets import QPushButton
+
+ui_path = resources.files(__package__) / "new_plan_regulation_widget.ui"
+FormClass, _ = uic.loadUiType(ui_path)
+
+
+class InputTypes(Enum):
+    TEXT_VALUE = 1
+    NUMERIC_VALUE = 2
+    CODE_VALUE = 3
+
+    TEXT_INFO = 4
+    NUMERIC_INFO = 5
+    CODE_INFO = 6
+
+    REGULATION_NUMBER = 7
+    RELATED_FILE = 8
+
+
+class NewPlanRegulationWidget(QWidget, FormClass):  # type: ignore
+    """A widget representation of a plan regulation."""
+
+    delete_signal = pyqtSignal(QWidget)
+
+    def __init__(self, regulation_type: str, parent=None):
+        super().__init__(parent)
+        self.setupUi(self)
+
+        # TYPES
+        self.plan_regulation_type: QLineEdit
+        self.form_layout: QFormLayout
+
+        self.add_input_btn: QPushButton
+        self.add_additional_information_btn: QPushButton
+        self.add_regulation_number_btn: QPushButton
+        self.add_file_btn: QPushButton
+        self.del_btn: QPushButton
+
+        # INIT
+        self.widgets: dict[InputTypes, list[QWidget]] = {}
+        self.plan_regulation_type.setText(regulation_type)
+        self.init_buttons()
+
+    def request_delete(self):
+        self.delete_signal.emit(self)
+
+    def init_buttons(self):
+        self.del_btn.setIcon(QgsApplication.getThemeIcon("mActionDeleteSelected.svg"))
+        self.del_btn.clicked.connect(self.request_delete)
+
+        input_menu = QMenu()
+        input_menu.addAction("Teksti").triggered.connect(lambda: self.add_input_field(InputTypes.TEXT_VALUE))
+        input_menu.addAction("Numeerinen").triggered.connect(lambda: self.add_input_field(InputTypes.NUMERIC_VALUE))
+        input_menu.addAction("Koodi").triggered.connect(lambda: self.add_input_field(InputTypes.CODE_VALUE))
+        self.add_input_btn.setMenu(input_menu)
+
+        additional_info_menu = QMenu()
+        additional_info_menu.addAction("Teksti").triggered.connect(lambda: self.add_input_field(InputTypes.TEXT_INFO))
+        additional_info_menu.addAction("Numeerinen").triggered.connect(
+            lambda: self.add_input_field(InputTypes.NUMERIC_INFO)
+        )
+        additional_info_menu.addAction("Koodi").triggered.connect(lambda: self.add_input_field(InputTypes.CODE_INFO))
+        self.add_additional_information_btn.setMenu(additional_info_menu)
+
+        self.add_regulation_number_btn.clicked.connect(lambda: self.add_input_field(InputTypes.REGULATION_NUMBER))
+        self.add_file_btn.clicked.connect(lambda: self.add_input_field(InputTypes.RELATED_FILE))
+
+    def add_input_field(self, input_field_type: InputTypes):
+        if input_field_type == InputTypes.TEXT_VALUE:
+            inputs = QTextEdit()
+            self.form_layout.addRow("Tekstiarvo", inputs)
+        elif input_field_type == InputTypes.NUMERIC_VALUE:
+            value_widget = QgsDoubleSpinBox()  # Or QgsSpinBox?
+            value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+            unit_widget = QLineEdit()
+            inputs = QHBoxLayout()
+            inputs.addWidget(value_widget)
+            inputs.addWidget(unit_widget)
+            self.form_layout.addRow("Numeerinen arvo", inputs)
+        elif input_field_type == InputTypes.CODE_VALUE:
+            code_widget = QComboBox()
+            code_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+            value_widget = QLineEdit()
+            inputs = QHBoxLayout()
+            inputs.addWidget(code_widget)
+            inputs.addWidget(value_widget)
+            # TODO: inputs.addItems()
+            self.form_layout.addRow("Koodiarvo", inputs)
+
+        elif input_field_type == InputTypes.TEXT_INFO:
+            inputs = QTextEdit()
+            self.form_layout.addRow("Lisätieto", inputs)
+        elif input_field_type == InputTypes.NUMERIC_INFO:
+            inputs = QgsDoubleSpinBox()
+            self.form_layout.addRow("Lisätieto", inputs)
+        elif input_field_type == InputTypes.CODE_INFO:
+            inputs = QComboBox()
+            # TODO: inputs.addItems()
+            self.form_layout.addRow("Lisätieto", inputs)
+
+        elif input_field_type == InputTypes.REGULATION_NUMBER:
+            inputs = QgsSpinBox()
+            self.form_layout.addRow("Määräysnumero", inputs)
+        elif input_field_type == InputTypes.RELATED_FILE:
+            inputs = QgsFileWidget()
+            self.form_layout.addRow("Liiteasiakirja", inputs)
+
+        if self.widgets.get(input_field_type) is None:
+            self.widgets[input_field_type] = [inputs]
+        else:
+            self.widgets[input_field_type].append(inputs)
diff --git a/arho_feature_template/gui/new_plan_regulation_widget.ui b/arho_feature_template/gui/new_plan_regulation_widget.ui
new file mode 100644
index 0000000..95b91b2
--- /dev/null
+++ b/arho_feature_template/gui/new_plan_regulation_widget.ui
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>694</width>
+    <height>108</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QFormLayout" name="form_layout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_4">
+       <property name="text">
+        <string>Kaavamääräyslaji</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QLineEdit" name="plan_regulation_type"/>
+       </item>
+       <item>
+        <widget class="QPushButton" name="del_btn">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>30</width>
+           <height>16777215</height>
+          </size>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QPushButton" name="add_input_btn">
+       <property name="text">
+        <string>Arvo</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="add_additional_information_btn">
+       <property name="text">
+        <string>Lisätieto</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="add_regulation_number_btn">
+       <property name="text">
+        <string>Määräysnumero</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="add_file_btn">
+       <property name="text">
+        <string>Liiteasiakirja</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <spacer name="horizontalSpacer_4">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Fixed</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="Line" name="line">
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>20</height>
+        </size>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_5">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Fixed</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/arho_feature_template/plugin.py b/arho_feature_template/plugin.py
index 7079fd9..ad9488a 100644
--- a/arho_feature_template/plugin.py
+++ b/arho_feature_template/plugin.py
@@ -9,6 +9,7 @@
 
 from arho_feature_template.core.feature_template_library import FeatureTemplater, TemplateGeometryDigitizeMapTool
 from arho_feature_template.core.plan_manager import PlanManager
+from arho_feature_template.gui.new_plan_regulation_group_form import NewPlanRegulationGroupForm
 from arho_feature_template.qgis_plugin_tools.tools.custom_logging import setup_logger, teardown_logger
 from arho_feature_template.qgis_plugin_tools.tools.i18n import setup_translation
 from arho_feature_template.qgis_plugin_tools.tools.resources import plugin_name
@@ -162,6 +163,14 @@ def initGui(self) -> None:  # noqa N802
             add_to_toolbar=True,
         )
 
+        self.new_plan_regulation_group = self.add_action(
+            "",
+            text="Luo kaavamääräysryhmä",
+            triggered_callback=self.open_plan_regulation_group_form,
+            add_to_menu=True,
+            add_to_toolbar=True,
+        )
+
     def on_map_tool_changed(self, new_tool: QgsMapTool, old_tool: QgsMapTool) -> None:  # noqa: ARG002
         if not isinstance(new_tool, TemplateGeometryDigitizeMapTool):
             self.template_dock_action.setChecked(False)
@@ -186,3 +195,7 @@ def dock_visibility_changed(self, visible: bool) -> None:  # noqa: FBT001
 
     def toggle_template_dock(self, show: bool) -> None:  # noqa: FBT001
         self.templater.template_dock.setUserVisible(show)
+
+    def open_plan_regulation_group_form(self):
+        self.new_plan_regulation_group_dialog = NewPlanRegulationGroupForm()
+        self.new_plan_regulation_group_dialog.exec_()