diff --git a/app/main/forms.py b/app/main/forms.py
index 66a4a00036b84b7f53f1aed6af8fa9622a193fe0..8ee9fd4e9d19d3f9d650c3d103db4132df327a8f 100644
--- a/app/main/forms.py
+++ b/app/main/forms.py
@@ -42,8 +42,16 @@ class HostForm(FlaskForm):
     # The list of IPs is dynamically created on the browser side
     # depending on the selected network
     ip = NoValidateSelectField('IP', choices=[])
-    name = StringField('Hostname')
+    name = StringField('Hostname',
+                       description='hostname must be 2-20 characters long and contain only letters, numbers and dash',
+                       validators=[validators.InputRequired(),
+                                   validators.Regexp(models.HOST_NAME_RE)],
+                       filters=[utils.lowercase_field])
+    description = StringField('Description')
+    mac_id = SelectField('MAC')
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self.network_id.choices = [(str(network.id), network.address) for network in models.Network.query.all()]
+        self.network_id.choices = [(str(network.id), network.vlan_name) for network in models.Network.query.all()]
+        self.mac_id.choices = [('', '')]
+        self.mac_id.choices.extend([(str(mac.id), mac.address) for mac in models.Mac.query.all()])
diff --git a/app/main/views.py b/app/main/views.py
index 6acd739ab407390d8a02ed2479d351764967ca03..6b058fb7e220d24374c07dd9fab6c3558cda02e8 100644
--- a/app/main/views.py
+++ b/app/main/views.py
@@ -65,10 +65,17 @@ def index():
 
 @bp.route('/items')
 @login_required
-def items_index():
+def list_items():
     return render_template('items.html')
 
 
+@bp.route('/items/create', methods=('GET', 'POST'))
+@login_groups_accepted('admin', 'create')
+def create_item():
+    form = None
+    return render_template('create_item.html', form=form)
+
+
 @bp.route('/view/<ics_id>')
 @login_required
 def view_item(ics_id):
@@ -119,9 +126,15 @@ def retrieve_qrcodes_name(kind):
     return jsonify(data=data)
 
 
-@bp.route('/hosts', methods=('GET', 'POST'))
+@bp.route('/hosts')
+@login_required
+def list_hosts():
+    return render_template('hosts.html')
+
+
+@bp.route('/hosts/create', methods=('GET', 'POST'))
 @login_groups_accepted('admin', 'create')
-def hosts_index():
+def create_host():
     # Try to get the network_id from the URL parameters
     # to display the form with the same selected network
     # when reloading the page (redirect after submit)
@@ -135,7 +148,9 @@ def hosts_index():
     if form.validate_on_submit():
         host = models.Host(ip=form.ip.data,
                            network_id=form.network_id.data,
-                           name=form.name.data)
+                           name=form.name.data,
+                           description=form.description.data or None,
+                           mac_id=form.mac_id.data or None)
         current_app.logger.debug(f'Trying to create: {host!r}')
         db.session.add(host)
         try:
@@ -144,14 +159,20 @@ def hosts_index():
             db.session.rollback()
             current_app.logger.warning(f'{e}')
             flash(f'{e}', 'error')
-        return redirect(url_for('main.hosts_index', network_id=host.network_id))
-    return render_template('hosts.html', form=form)
+        else:
+            flash(f'Host {host} created!', 'success')
+        return redirect(url_for('main.create_host', network_id=host.network_id))
+    return render_template('create_host.html', form=form)
 
 
 @bp.route('/_retrieve_hosts')
 @login_required
 def retrieve_hosts():
-    data = [(host.name, host.ip, host.network.vlan_name) for host in models.Host.query.all()]
+    data = [(host.name,
+             host.ip,
+             host.description,
+             str(host.mac),
+             host.network.vlan_name) for host in models.Host.query.all()]
     return jsonify(data=data)
 
 
diff --git a/app/models.py b/app/models.py
index 7108bfa982ae0a77fd07d370950304d7f02f8a1c..d76880a98343be9ac121fc0faf270606948238d3 100644
--- a/app/models.py
+++ b/app/models.py
@@ -27,6 +27,7 @@ from . import utils
 
 
 ICS_ID_RE = re.compile('[A-Z]{3}[0-9]{3}')
+HOST_NAME_RE = re.compile('^[a-z0-9\-]{2,20}$')
 make_versioned(plugins=[FlaskUserPlugin()])
 
 
@@ -420,12 +421,23 @@ class Host(db.Model):
         else:
             super().__init__(ip=ip, **kwargs)
 
+    @validates('name')
+    def validate_name(self, key, string):
+        """Ensure the hostname matches the required format"""
+        if string is None:
+            return None
+        # Force the string to lowercase
+        lower_string = string.lower()
+        if HOST_NAME_RE.fullmatch(lower_string) is None:
+            raise ValidationError('Host name shall match [a-z0-9\-]{2,20}')
+        return lower_string
+
     @property
     def address(self):
         return ipaddress.ip_address(self.ip)
 
     def __str__(self):
-        return str(self.ip)
+        return str(self.name)
 
     def __repr__(self):
         return f'Host(id={self.id}, network_id={self.network_id}, ip={self.ip}, name={self.name}, description={self.description}, mac={self.mac})'
diff --git a/app/templates/_helpers.html b/app/templates/_helpers.html
index 8c761e0919d77223bc39e320c07f983cf45a6769..22aff7a4fe6e0400fc488c2d98ccd7b5eb9c18fd 100644
--- a/app/templates/_helpers.html
+++ b/app/templates/_helpers.html
@@ -15,3 +15,27 @@
     {{ link_to_item(ics_id) }}
   {% endfor %}
 {%- endmacro %}
+
+{% macro render_field(field) -%}
+  {% set field_class = kwargs.pop('class_', '') + ' form-control' %}
+  {% if field.errors %}
+    {% set field_class = field_class + ' is-invalid' %}
+  {% endif %}
+
+  <div class="form-group row">
+    {{ field.label(class_="col-sm-2 col-form-label") }}
+    <div class="col-sm-10">
+      {{ field(class_=field_class) }}
+      {% if field.description %}
+        <small class="form-text text-muted">
+          {{ field.description|safe }}
+        </small>
+      {% endif %}
+      {% if field.errors %}
+        <div class="invalid-feedback">
+          {{ field.errors|join(' / ') }}
+        </div>
+      {% endif %}
+    </div>
+  </div>
+{%- endmacro %}
diff --git a/app/templates/base.html b/app/templates/base.html
index b853c9e03a2dc6247bf0cb663bea6b74ee6fc456..4b1e84d7526cb01723b0fedee8ee3fa5c337dec1 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -23,8 +23,8 @@
       <div class="collapse navbar-collapse" id="navbarSupportedContent">
         <div class="navbar-nav mr-auto">
           {% set path = request.path %}
-          <a class="nav-item nav-link {{ is_active(path.startswith("/items")) }}" href="{{ url_for('main.items_index') }}">Items</a>
-          <a class="nav-item nav-link {{ is_active(path == "/hosts") }}" href="{{ url_for('main.hosts_index') }}">Hosts</a>
+          <a class="nav-item nav-link {{ is_active(path.startswith("/items")) }}" href="{{ url_for('main.list_items') }}">Items</a>
+          <a class="nav-item nav-link {{ is_active(path.startswith("/hosts")) }}" href="{{ url_for('main.list_hosts') }}">Hosts</a>
           <div class="dropdown {{ is_active(path.startswith("/qrcodes")) }}">
             <a class="nav-link dropdown-toggle" href="#" id="qrcodesDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
               QR Codes
diff --git a/app/templates/create_host.html b/app/templates/create_host.html
new file mode 100644
index 0000000000000000000000000000000000000000..ad7c97336d0ba06e5a5bbf87f38f14f00a6425db
--- /dev/null
+++ b/app/templates/create_host.html
@@ -0,0 +1,35 @@
+{%- extends "base.html" %}
+{% from "_helpers.html" import render_field %}
+
+{% block title %}Hosts - CSEntry{% endblock %}
+
+{% block main %}
+  <ul class="nav nav-tabs">
+    <li class="nav-item">
+      <a class="nav-link" href="{{ url_for('main.list_hosts') }}">List hosts</a>
+    </li>
+    <li class="nav-item">
+      <a class="nav-link active" href="{{ url_for('main.create_host') }}">Register new host</a>
+    </li>
+  </ul>
+
+  <br>
+
+  <form id="hostForm" method="POST">
+    {{ form.hidden_tag() }}
+    {{ render_field(form.network_id) }}
+    {{ render_field(form.ip) }}
+    {{ render_field(form.name, class_="text-lowercase") }}
+    {{ render_field(form.description) }}
+    {{ render_field(form.mac_id) }}
+    <div class="form-group row">
+      <div class="col-sm-10">
+        <button type="submit" class="btn btn-primary">Submit</button>
+      </div>
+    </div>
+  </form>
+{%- endblock %}
+
+{% block csentry_scripts %}
+  <script src="{{ url_for('static', filename='js/hosts.js') }}"></script>
+{% endblock %}
diff --git a/app/templates/create_item.html b/app/templates/create_item.html
new file mode 100644
index 0000000000000000000000000000000000000000..56a5f18812f57c8c8715e5d5d3ed25a0d57705ed
--- /dev/null
+++ b/app/templates/create_item.html
@@ -0,0 +1,26 @@
+{%- extends "base.html" %}
+
+{% block title %}Items - CSEntry{% endblock %}
+
+{% block main %}
+  <ul class="nav nav-tabs">
+    <li class="nav-item">
+      <a class="nav-link" href="{{ url_for('main.list_items') }}">List items</a>
+    </li>
+    <li class="nav-item">
+      <a class="nav-link active" href="{{ url_for('main.create_item') }}">Register new item</a>
+    </li>
+  </ul>
+
+  <br>
+
+  <div class="card">
+    <h4 class="card-header">Register new item</h4>
+    <div class="card-body">
+    </div>
+  </div>
+{%- endblock %}
+
+{% block csentry_scripts %}
+  <script src="{{ url_for('static', filename='js/items.js') }}"></script>
+{% endblock %}
diff --git a/app/templates/hosts.html b/app/templates/hosts.html
index 6f22bf9e47386582e0822d10fd0912bc14ed07c1..344106cd581af0833c25099a47bbabea8b041e13 100644
--- a/app/templates/hosts.html
+++ b/app/templates/hosts.html
@@ -3,45 +3,24 @@
 {% block title %}Hosts - CSEntry{% endblock %}
 
 {% block main %}
-  <div class="card">
-    <h4 class="card-header">Register new host</h4>
-    <div class="card-body">
-      <form id="hostForm" method="POST">
-        {{ form.hidden_tag() }}
-        <div class="form-group row">
-          {{ form.network_id.label(class_="col-sm-2 col-form-label") }}
-          <div class="col-sm-10">
-            {{ form.network_id(class_="form-control") }}
-          </div>
-        </div>
-        <div class="form-group row">
-          {{ form.ip.label(class_="col-sm-2 col-form-label") }}
-          <div class="col-sm-10">
-            {{ form.ip(class_="form-control") }}
-          </div>
-        </div>
-        <div class="form-group row">
-          {{ form.name.label(class_="col-sm-2 col-form-label") }}
-          <div class="col-sm-10">
-            {{ form.name(class_="form-control") }}
-          </div>
-        </div>
-        <div class="form-group row">
-          <div class="col-sm-10">
-            <button type="submit" class="btn btn-primary">Submit</button>
-          </div>
-        </div>
-      </form>
-    </div>
-  </div>
+  <ul class="nav nav-tabs">
+    <li class="nav-item">
+      <a class="nav-link active" href="{{ url_for('main.list_hosts') }}">List hosts</a>
+    </li>
+    <li class="nav-item">
+      <a class="nav-link" href="{{ url_for('main.create_host') }}">Register new host</a>
+    </li>
+  </ul>
 
-  <hr class="separator">
+  <br>
 
   <table id="hosts_table" class="table table-bordered table-hover table-sm">
     <thead>
       <tr>
         <th>Hostname</th>
         <th>IP</th>
+        <th>Description</th>
+        <th>MAC</th>
         <th>Network</th>
       </tr>
     </thead>
diff --git a/app/templates/items.html b/app/templates/items.html
index adfbdb337337bd4b952acdec554941f1664d141d..9576fc17f967356022172e8da89d69136aae734b 100644
--- a/app/templates/items.html
+++ b/app/templates/items.html
@@ -3,13 +3,17 @@
 {% block title %}Items - CSEntry{% endblock %}
 
 {% block main %}
-  <div class="card">
-    <h4 class="card-header">Register new item</h4>
-    <div class="card-body">
-    </div>
-  </div>
+  <ul class="nav nav-tabs">
+    <li class="nav-item">
+      <a class="nav-link active" href="{{ url_for('main.list_items') }}">List items</a>
+    </li>
+    <li class="nav-item">
+      <a class="nav-link" href="{{ url_for('main.create_item') }}">Register new item</a>
+    </li>
+  </ul>
+
+  <br>
 
-  <hr class="separator">
   <table id="items_table" class="table table-bordered table-hover table-sm">
     <thead>
       <tr>
diff --git a/app/utils.py b/app/utils.py
index a20b7e9bc3e8d81c6503f2ce1a853e32deaa9c1c..aab9a5a15cdd8eef01e68cab5f4714b86bbd5bc4 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -121,3 +121,11 @@ def get_query(query, args):
         except (sa.exc.InvalidRequestError, AttributeError) as e:
             raise CSEntryError('Invalid query arguments', status_code=422)
     return query
+
+
+def lowercase_field(value):
+    """Filter to force form value to lowercase"""
+    try:
+        return value.lower()
+    except AttributeError:
+        return value