diff --git a/app/assets/javascripts/discourse/app/controllers/create-invite.js b/app/assets/javascripts/discourse/app/controllers/create-invite.js
index 3237366b041..d24e4525685 100644
--- a/app/assets/javascripts/discourse/app/controllers/create-invite.js
+++ b/app/assets/javascripts/discourse/app/controllers/create-invite.js
@@ -1,11 +1,11 @@
 import Controller from "@ember/controller";
 import { action } from "@ember/object";
-import { equal } from "@ember/object/computed";
+import { empty, notEmpty } from "@ember/object/computed";
 import discourseComputed from "discourse-common/utils/decorators";
 import { extractError } from "discourse/lib/ajax-error";
+import { getNativeContact } from "discourse/lib/pwa-utils";
 import { bufferedProperty } from "discourse/mixins/buffered-content";
 import ModalFunctionality from "discourse/mixins/modal-functionality";
-import { getNativeContact } from "discourse/lib/pwa-utils";
 import Group from "discourse/models/group";
 import Invite from "discourse/models/invite";
 import I18n from "I18n";
@@ -24,7 +24,8 @@ export default Controller.extend(
     limitToEmail: false,
     autogenerated: false,
 
-    type: "link",
+    isLink: empty("buffered.email"),
+    isEmail: notEmpty("buffered.email"),
 
     onShow() {
       Group.findAll().then((groups) => {
@@ -52,10 +53,7 @@ export default Controller.extend(
     },
 
     setInvite(invite) {
-      this.setProperties({
-        invite,
-        type: invite.email ? "email" : "link",
-      });
+      this.set("invite", invite);
     },
 
     setAutogenerated(value) {
@@ -70,7 +68,7 @@ export default Controller.extend(
       const data = { ...this.buffered.buffer };
 
       if (data.groupIds !== undefined) {
-        data.group_ids = data.groupIds;
+        data.group_ids = data.groupIds.length > 0 ? data.groupIds : "";
         delete data.groupIds;
       }
 
@@ -80,13 +78,12 @@ export default Controller.extend(
         delete data.topicTitle;
       }
 
-      if (this.type === "link") {
-        if (this.buffered.get("email")) {
-          data.email = "";
-          data.custom_message = "";
+      if (this.isLink) {
+        if (this.invite.email) {
+          data.email = data.custom_message = "";
         }
-      } else if (this.type === "email") {
-        if (this.buffered.get("max_redemptions_allowed") > 1) {
+      } else if (this.isEmail) {
+        if (this.invite.max_redemptions_allowed > 1) {
           data.max_redemptions_allowed = 1;
         }
 
@@ -106,7 +103,7 @@ export default Controller.extend(
           this.rollbackBuffer();
           this.setAutogenerated(opts.autogenerated);
           if (!this.autogenerated) {
-            if (this.type === "email" && opts.sendEmail) {
+            if (this.isEmail && opts.sendEmail) {
               this.send("closeModal");
             } else {
               this.appEvents.trigger("modal-body:flash", {
@@ -126,9 +123,6 @@ export default Controller.extend(
         );
     },
 
-    isLink: equal("type", "link"),
-    isEmail: equal("type", "email"),
-
     @discourseComputed(
       "currentUser.staff",
       "siteSettings.invite_link_max_redemptions_limit",
@@ -156,46 +150,16 @@ export default Controller.extend(
       return staff || groups.any((g) => g.owner);
     },
 
-    @discourseComputed("type", "buffered.email")
-    disabled(type, email) {
-      if (type === "email") {
-        return !email;
-      }
-
-      return false;
-    },
-
-    @discourseComputed("buffered.hasBufferedChanges", "invite.email", "type")
-    changed(hasBufferedChanges, inviteEmail, type) {
-      return hasBufferedChanges || (inviteEmail ? "email" : "link") !== type;
-    },
-
-    @discourseComputed("currentUser.staff", "type")
-    hasAdvanced(staff, type) {
-      return staff || type === "email";
+    @discourseComputed("currentUser.staff", "isEmail", "canInviteToGroup")
+    hasAdvanced(staff, isEmail, canInviteToGroup) {
+      return staff || isEmail || canInviteToGroup;
     },
 
     @action
     copied() {
-      if (this.type === "email" && !this.buffered.get("email")) {
-        return this.appEvents.trigger("modal-body:flash", {
-          text: I18n.t("user.invited.invite.blank_email"),
-          messageClass: "error",
-        });
-      }
-
       this.save({ sendEmail: false, copy: true });
     },
 
-    @action
-    toggleLimitToEmail() {
-      const limitToEmail = !this.limitToEmail;
-      this.setProperties({
-        limitToEmail,
-        type: limitToEmail ? "email" : "link",
-      });
-    },
-
     @action
     saveInvite(sendEmail) {
       this.appEvents.trigger("modal-body:clearFlash");
diff --git a/app/assets/javascripts/discourse/app/templates/components/choose-topic.hbs b/app/assets/javascripts/discourse/app/templates/components/choose-topic.hbs
index bae33d6b875..7d384bccb21 100644
--- a/app/assets/javascripts/discourse/app/templates/components/choose-topic.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/choose-topic.hbs
@@ -1,4 +1,6 @@
-<label for="choose-topic-title">{{i18n labelText}}</label>
+<label for="choose-topic-title">
+  {{#if labelIcon}}{{d-icon labelIcon}}{{/if}}{{i18n labelText}}
+</label>
 
 {{text-field value=topicTitle placeholderKey="choose_topic.title.placeholder" id="choose-topic-title"}}
 
diff --git a/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs b/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs
index bb629c45272..2ff6e7de08c 100644
--- a/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/future-date-input.hbs
@@ -1,6 +1,8 @@
 <div class="future-date-input">
   <div class="control-group">
-    <label class={{labelClasses}}>{{displayLabel}}</label>
+    <label class={{labelClasses}}>
+      {{#if displayLabelIcon}}{{d-icon displayLabelIcon}}{{/if}}{{displayLabel}}
+    </label>
     {{future-date-input-selector
       minimumResultsForSearch=-1
       statusType=statusType
diff --git a/app/assets/javascripts/discourse/app/templates/modal/create-invite.hbs b/app/assets/javascripts/discourse/app/templates/modal/create-invite.hbs
index 941531c2631..9063845f08d 100644
--- a/app/assets/javascripts/discourse/app/templates/modal/create-invite.hbs
+++ b/app/assets/javascripts/discourse/app/templates/modal/create-invite.hbs
@@ -13,33 +13,31 @@
       </div>
     </div>
 
-    <p>{{expiresAtLabel}}</p>
+    <div class="input-group input-expires-at">
+      <label>{{d-icon "far-clock"}}{{expiresAtLabel}}</label>
+    </div>
 
-    <div class="input-group invite-type">
-      {{input type="checkbox" id="invite-type" checked=limitToEmail click=(action "toggleLimitToEmail")}}
-      <label for="invite-type">{{i18n "user.invited.invite.restrict_email"}}</label>
-
-      {{#if isEmail}}
-        <div class="invite-input-with-button">
-          {{input
-            id="invite-email"
-            value=buffered.email
-            placeholderKey="topic.invite_reply.email_placeholder"
+    <div class="input-group input-email">
+      <label for="invite-email">{{d-icon "envelope"}}{{i18n "user.invited.invite.restrict_email"}}</label>
+      <div class="invite-input-with-button">
+        {{input
+          id="invite-email"
+          value=buffered.email
+          placeholderKey="topic.invite_reply.email_placeholder"
+        }}
+        {{#if capabilities.hasContactPicker}}
+          {{d-button
+            icon="address-book"
+            action=(action "searchContact")
+            class="btn-primary open-contact-picker"
           }}
-          {{#if capabilities.hasContactPicker}}
-            {{d-button
-              icon="address-book"
-              action=(action "searchContact")
-              class="btn-primary open-contact-picker"
-            }}
-          {{/if}}
-        </div>
-      {{/if}}
+        {{/if}}
+      </div>
     </div>
 
     {{#if isLink}}
       <div class="input-group invite-max-redemptions">
-        <label for="invite-max-redemptions">{{i18n "user.invited.invite.max_redemptions_allowed"}}</label>
+        <label for="invite-max-redemptions">{{d-icon "users"}}{{i18n "user.invited.invite.max_redemptions_allowed"}}</label>
         {{input
           id="invite-max-redemptions"
           type="number"
@@ -50,10 +48,10 @@
       </div>
     {{/if}}
 
-    {{#if isEmail}}
-      {{#if showAdvanced}}
+    {{#if showAdvanced}}
+      {{#if isEmail}}
         <div class="input-group invite-custom-message">
-          <label for="invite-message">{{i18n "user.invited.invite.custom_message"}}</label>
+          <label for="invite-message">{{d-icon "envelope"}}{{i18n "user.invited.invite.custom_message"}}</label>
           {{textarea id="invite-message" value=buffered.custom_message}}
         </div>
       {{/if}}
@@ -66,12 +64,13 @@
             selectedTopicId=buffered.topicId
             topicTitle=buffered.topicTitle
             additionalFilters="status:public"
+            labelIcon="hand-point-right"
             label="user.invited.invite.invite_to_topic"
           }}
         </div>
       {{else if buffered.topicTitle}}
-        <div class="input-group">
-          <label for="invite-topic">{{i18n "user.invited.invite.invite_to_topic"}}</label>
+        <div class="input-group invite-to-topic">
+          <label for="invite-topic">{{d-icon "hand-point-right"}}{{i18n "user.invited.invite.invite_to_topic"}}</label>
           {{input
             name="invite-topic"
             class="invite-topic"
@@ -85,7 +84,7 @@
     {{#if showAdvanced}}
       {{#if canInviteToGroup}}
         <div class="input-group invite-to-groups">
-          <label>{{i18n "user.invited.invite.add_to_groups"}}</label>
+          <label>{{d-icon "users"}}{{i18n "user.invited.invite.add_to_groups"}}</label>
           {{group-chooser
             content=allGroups
             value=buffered.groupIds
@@ -100,6 +99,7 @@
       {{#if currentUser.staff}}
         <div class="input-group invite-expires-at">
           {{future-date-input
+            displayLabelIcon="far-clock"
             displayLabel=(i18n "user.invited.invite.expires_at")
             includeDateTime=true
             includeMidFuture=true
@@ -118,7 +118,6 @@
     label="user.invited.invite.save_invite"
     class="btn-primary save-invite"
     action=(action "saveInvite")
-    disabled=disabled
   }}
 
   {{#if isEmail}}
@@ -127,7 +126,6 @@
       label=(if invite.emailed "user.invited.reinvite" "user.invited.invite.send_invite_email")
       class="btn-primary send-invite"
       action=(action "saveInvite" true)
-      disabled=disabled
     }}
   {{/if}}
 
diff --git a/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js b/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js
index 1aed75b4ad7..80afabea8e9 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js
@@ -1,7 +1,6 @@
 import { click, fillIn, visit } from "@ember/test-helpers";
 import { acceptance } from "discourse/tests/helpers/qunit-helpers";
 import { test } from "qunit";
-import I18n from "I18n";
 
 acceptance("Invites - Create & Edit Invite Modal", function (needs) {
   let deleted;
@@ -23,7 +22,16 @@ acceptance("Invites - Create & Edit Invite Modal", function (needs) {
     };
 
     server.post("/invites", () => helper.response(inviteData));
-    server.put("/invites/1", () => helper.response(inviteData));
+    server.put("/invites/1", (request) => {
+      const data = helper.parsePostData(request.requestBody);
+      if (data.email === "error") {
+        return helper.response(422, {
+          errors: ["error isn't a valid email address."],
+        });
+      } else {
+        return helper.response(inviteData);
+      }
+    });
 
     server.delete("/invites", () => {
       deleted = true;
@@ -95,11 +103,11 @@ acceptance("Invites - Create & Edit Invite Modal", function (needs) {
     await visit("/u/eviltrout/invited/pending");
     await click(".invite-controls .btn:first-child");
 
-    await click("#invite-type");
+    await fillIn("#invite-email", "error");
     await click(".invite-link .btn");
     assert.equal(
       find("#modal-alert").text(),
-      I18n.t("user.invited.invite.blank_email")
+      "error isn't a valid email address."
     );
   });
 });
@@ -172,11 +180,9 @@ acceptance("Invites - Email Invites", function (needs) {
     await visit("/u/eviltrout/invited/pending");
     await click(".invite-controls .btn:first-child");
 
-    await click("#invite-type");
-
     assert.ok(find("#invite-email").length, "shows email field");
-
     await fillIn("#invite-email", "test@example.com");
+
     assert.ok(find(".save-invite").length, "shows save without email button");
     await click(".save-invite");
     assert.ok(
diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss
index c6649014b29..7da41a3b239 100644
--- a/app/assets/stylesheets/common/base/modal.scss
+++ b/app/assets/stylesheets/common/base/modal.scss
@@ -832,7 +832,7 @@
 .create-invite-modal,
 .share-topic-modal {
   .input-group {
-    margin-bottom: 1em;
+    margin-bottom: 0.5em;
 
     &:last-child {
       margin-bottom: 0;
@@ -841,24 +841,24 @@
     input[type="text"] {
       width: 100%;
     }
-  }
 
-  .invite-type {
-    input[type="checkbox"] {
-      display: inline;
-      vertical-align: middle;
-      margin-top: -1px;
+    textarea#invite-message,
+    &.invite-to-topic input[type="text"],
+    .group-chooser,
+    .user-chooser,
+    .future-date-input-selector {
+      margin-left: 25px;
+      width: calc(100% - 25px);
     }
 
-    label {
-      display: inline-block;
+    &.invite-to-topic input[type="radio"] {
+      margin-left: 10px;
     }
-  }
 
-  .group-chooser,
-  .user-chooser,
-  .future-date-input-selector {
-    width: 100%;
+    label .d-icon {
+      color: var(--primary-medium);
+      margin-right: 10px;
+    }
   }
 
   .input-group input[type="text"],
@@ -868,10 +868,6 @@
     height: 34px;
   }
 
-  .input-group .btn {
-    vertical-align: top;
-  }
-
   .invite-input-with-button {
     display: flex;
 
@@ -880,6 +876,16 @@
     }
   }
 
+  .input-group.input-expires-at,
+  .input-group.input-email,
+  .input-group.invite-max-redemptions {
+    margin-bottom: 0;
+
+    input[type="text"] {
+      width: unset;
+    }
+  }
+
   .future-date-input {
     .date-picker-wrapper {
       input {
@@ -900,6 +906,25 @@
     }
   }
 
+  .input-group.input-email {
+    align-items: baseline;
+    display: flex;
+
+    label {
+      display: inline;
+    }
+
+    .invite-input-with-button {
+      display: inline-flex;
+      flex: 1;
+
+      input[type="text"] {
+        flex: 1;
+        margin-left: 5px;
+      }
+    }
+  }
+
   .invite-max-redemptions {
     label {
       display: inline;
@@ -910,6 +935,12 @@
     }
   }
 
+  .invite-to-topic {
+    #choose-topic-title {
+      margin-bottom: 0;
+    }
+  }
+
   .show-advanced {
     margin-left: auto;
     margin-right: 0;
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 983f955b02a..63adc3abb4a 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1534,7 +1534,7 @@ en:
           new_title: "Create Invite"
           edit_title: "Edit Invite"
 
-          instructions: "Share this link to instantly grant access to this site:"
+          instructions: "Share this link to instantly grant access to this site"
           copy_link: "copy link"
           expires_in_time: "Expires in %{time}."
           expired_at_time: "Expired at %{time}."
@@ -1542,21 +1542,20 @@ en:
           show_advanced: "Show Advanced Options"
           hide_advanced: "Hide Advanced Options"
 
-          restrict_email: "Restrict the invite to one email address"
+          restrict_email: "Restrict to one email address"
 
-          max_redemptions_allowed: "Max number of uses:"
+          max_redemptions_allowed: "Max uses"
 
-          add_to_groups: "Add to groups:"
-          invite_to_topic: "Send to topic on first login:"
-          expires_at: "Expire after:"
-          custom_message: "Optional personal message:"
+          add_to_groups: "Add to groups"
+          invite_to_topic: "Arrive at this topic"
+          expires_at: "Expire after"
+          custom_message: "Optional personal message"
 
           send_invite_email: "Save and Send Email"
           save_invite: "Save Invite"
 
           invite_saved: "Invite saved."
           invite_copied: "Invite link copied."
-          blank_email: "Invite link not copied. Email address is required."
 
         bulk_invite:
           none: "No invitations to display on this page."