[tor-commits] [tor-browser] 20/311: Bug 1745026 - Part 1: Implement basic opt-in modal design for Firefox Suggest. r=adw, a=dsmith

gitolite role git at cupani.torproject.org
Tue Apr 26 15:27:00 UTC 2022


This is an automated email from the git hooks/post-receive script.

pierov pushed a commit to branch geckoview-99.0.1-11.0-1
in repository tor-browser.

commit dcceeea907faffe2bc1a6ee272f7532ac4fe18a2
Author: Daisuke Akatsuka <daisuke at birchill.co.jp>
AuthorDate: Fri Jan 7 21:33:03 2022 +0000

    Bug 1745026 - Part 1: Implement basic opt-in modal design for Firefox Suggest. r=adw, a=dsmith
    
    Differential Revision: https://phabricator.services.mozilla.com/D133467
---
 browser/components/urlbar/UrlbarQuickSuggest.jsm   |   8 +-
 .../components/urlbar/content/firefoxSuggest.ftl   |  20 +
 .../urlbar/content/quicksuggestOnboarding.css      | 223 +++++++++--
 .../urlbar/content/quicksuggestOnboarding.html     |  93 +++++
 .../urlbar/content/quicksuggestOnboarding.js       | 109 ++---
 .../urlbar/content/quicksuggestOnboarding.xhtml    |  48 ---
 .../quicksuggestOnboarding_illustration.svg        | 104 -----
 .../content/quicksuggestOnboarding_magglass.svg    |  34 ++
 .../quicksuggestOnboarding_magglass_animation.svg  |   4 +
 .../urlbar/docs/firefox-suggest-telemetry.rst      |  21 +-
 browser/components/urlbar/jar.mn                   |   5 +-
 .../quicksuggest/browser/browser_quicksuggest.js   |  61 ---
 .../browser/browser_quicksuggest_configuration.js  |  27 +-
 .../browser_quicksuggest_onboardingDialog.js       | 437 ++++++++++++++-------
 .../urlbar/tests/quicksuggest/browser/head.js      |   4 +
 toolkit/components/telemetry/Events.yaml           |  23 +-
 16 files changed, 775 insertions(+), 446 deletions(-)

diff --git a/browser/components/urlbar/UrlbarQuickSuggest.jsm b/browser/components/urlbar/UrlbarQuickSuggest.jsm
index 5aab8e5c9a127..d32a872cf8154 100644
--- a/browser/components/urlbar/UrlbarQuickSuggest.jsm
+++ b/browser/components/urlbar/UrlbarQuickSuggest.jsm
@@ -45,15 +45,15 @@ const RESTARTS_PREF = "quicksuggest.seenRestarts";
 // These values are used in telemetry events, so be careful about changing them.
 const ONBOARDING_CHOICE = {
   ACCEPT: "accept",
+  REJECT: "reject",
   DISMISSED_ESCAPE_KEY: "dismissed_escape_key",
   DISMISSED_OTHER: "dismissed_other",
   LEARN_MORE: "learn_more",
   NOT_NOW: "not_now_link",
-  SETTINGS: "settings",
 };
 
 const ONBOARDING_URI =
-  "chrome://browser/content/urlbar/quicksuggestOnboarding.xhtml";
+  "chrome://browser/content/urlbar/quicksuggestOnboarding.html";
 
 // This is a score in the range [0, 1] used by the provider to compare
 // suggestions from remote settings to suggestions from Merino. Remote settings
@@ -274,10 +274,8 @@ class Suggestions {
           fromChrome: true,
         });
         break;
-      case ONBOARDING_CHOICE.SETTINGS:
-        win.openPreferences("privacy-locationBar");
-        break;
       case ONBOARDING_CHOICE.ACCEPT:
+      case ONBOARDING_CHOICE.REJECT:
       case ONBOARDING_CHOICE.NOT_NOW:
         // No other action required.
         break;
diff --git a/browser/components/urlbar/content/firefoxSuggest.ftl b/browser/components/urlbar/content/firefoxSuggest.ftl
index ec724131d60c1..712d89ce77065 100644
--- a/browser/components/urlbar/content/firefoxSuggest.ftl
+++ b/browser/components/urlbar/content/firefoxSuggest.ftl
@@ -84,3 +84,23 @@ addressbar-firefox-suggest-info-sponsored = Based on your selection, you’ll re
 # Sponsored suggestions: off
 # Data collection: on
 addressbar-firefox-suggest-info-data = Based on your selection, you won’t receive suggestions from the web or sponsored sites. We will process your search query data to develop the { -firefox-suggest-brand-name } feature.
+
+## These strings are used in the introduction pane of the Firefox Suggest online
+## onboarding opt-in dialog.
+
+firefox-suggest-onboarding-introduction-title = Make sure you’ve got our newest search experience
+firefox-suggest-onboarding-introduction-button = Next
+
+## These strings are used in the main pane of the Firefox Suggest online
+## onboarding opt-in dialog. Options are displayed as radio buttons with a label
+## followed by a description.
+
+firefox-suggest-onboarding-main-title = We’re building a richer search experience
+firefox-suggest-onboarding-main-description = Finding the best of the web should be easier. Allowing { -vendor-short-name } to process your search queries will help develop our { -firefox-suggest-brand-name } feature, while keeping your privacy top of mind.
+firefox-suggest-onboarding-main-accept-option-label =
+    Allow improved search experience. <a data-l10n-name="firefox-suggest-onboarding-learn-more-link">Learn more</a>
+firefox-suggest-onboarding-main-accept-option-description = Include suggestions for a more curated web experience.
+firefox-suggest-onboarding-main-reject-option-label = Keep my default experience.
+firefox-suggest-onboarding-main-reject-option-description = Don’t allow search query processing.
+firefox-suggest-onboarding-main-submit-button = Save preferences
+firefox-suggest-onboarding-main-skip-link = Skip action
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding.css b/browser/components/urlbar/content/quicksuggestOnboarding.css
index 46beef86a6cc4..f48712037970a 100644
--- a/browser/components/urlbar/content/quicksuggestOnboarding.css
+++ b/browser/components/urlbar/content/quicksuggestOnboarding.css
@@ -2,40 +2,219 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#infoContainer {
+/**
+ * We follow the example of the upgrade dialog for font sizes, line heights,
+ * etc. See: https://searchfox.org/mozilla-central/source/browser/themes/shared/upgradeDialog.css
+ */
+
+:root {
+  /* As this dialog is designed under assuming the base font size is 11px,
+     specify image size using current font-size. */
+  --introduction-logo-width: calc(158 / 11 * 1em);
+  --introduction-logo-height: calc(114 / 11 * 1em);
+  --main-logo-width: calc(100 / 11 * 1em);
+  --main-logo-height: calc(64 / 11 * 1em);
+  /* --fixed-large-margin is constant regardless of compact mode. */
+  --fixed-large-margin: 24px;
+  --large-margin: 24px;
+  --small-margin: 16px;
+  --section-vertical-padding: 32px;
+  --section-horizontal-padding: 64px;
+}
+
+body.compact {
+  /* 15px is the usual font-size. */
+  font-size: 13px;
+  --main-logo-width: calc(100 / 13 * 1em);
+  --main-logo-height: calc(64 / 13 * 1em);
+  --large-margin: 12px;
+  --small-margin: 8px;
+  --section-vertical-padding: 16px;
+  --section-horizontal-padding: 32px;
+}
+
+section {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
   text-align: center;
-  padding: 1em 0;
+  padding: var(--section-vertical-padding) var(--section-horizontal-padding);
+  width: 536px;
+  /* This is the natural height of the main section. */
+  min-height: 587px;
+}
+
+body.compact section {
+  /* This is the natural height of the main section in compact mode. */
+  min-height: 450px;
+}
+
+.title {
+  font-size: 1.6em;
+  font-weight: 600;
+  line-height: 1.5;
+}
+
+.logo {
+  background-repeat: no-repeat;
+  background-position: center;
+  background-size: contain;
+  border: none;
+}
+
+.pager > span {
+  display: inline-block;
+  border-radius: 3px;
+  width: 6px;
+  height: 6px;
+  background-color: var(--in-content-border-color);
+  margin-inline: 4px;
+}
+
+.pager > .current {
+  background-color: var(--in-content-primary-button-background);
+}
+
+#introduction-section .logo {
+  background-image: url("quicksuggestOnboarding_magglass_animation.svg");
+  width: var(--introduction-logo-width);
+  height: var(--introduction-logo-height);
+  margin-block-end: var(--large-margin);
+}
+
+ at media (prefers-reduced-motion: reduce) {
+  #introduction-section .logo {
+    background-image: url("quicksuggestOnboarding_magglass.svg");
+  }
+}
+
+#introduction-section .title {
+  margin-block-end: var(--large-margin);
+}
+
+#main-section {
+  display: none;
+}
+
+#main-section .logo {
+  background-image: url("quicksuggestOnboarding_magglass.svg");
+  width: var(--main-logo-width);
+  height: var(--main-logo-height);
+  margin-block-end: var(--large-margin);
+}
+
+#main-section .title {
+  margin-block-end: var(--large-margin);
+}
+
+#main-section .description {
+  margin-block: 0 var(--fixed-large-margin);
+  font-size: 1.1em;
+  font-weight: 400;
+  line-height: 1.6;
+}
+
+#main-section .option {
+  border-radius: 4px;
+  border: 2px solid var(--in-content-box-info-background);
+  display: flex;
+  text-align: start;
+  padding: var(--small-margin);
+  width: calc(100% - (var(--small-margin) + 2px) * 2);
+  flex-direction: row;
+  position: relative;
+}
+
+#main-section .option.selected {
+  border-color: var(--in-content-primary-button-background);
+}
+
+#main-section .option.accept {
+  margin-block-end: var(--small-margin);
+}
+
+#main-section .option.reject {
+  margin-block-end: var(--fixed-large-margin);
+}
+
+#main-section .option > label {
+  /* Make whole option area selectable for the radio button. */
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
+
+body:not(.compact) #main-section .option > input {
+  /* Vertically align the radio button with the .option-label. */
+  margin-block-start: 0.25em;
+}
+
+#main-section .option > div {
+  /* Make this area be front than label to make the link included clickable.
+     And, make this area not recieve pointer-events so that this area as well
+     will be selectable area for the radio. */
+  z-index: 1;
+  pointer-events: none;
+}
+
+#main-section .option > div a {
+  /* Make a clickable explicitly since the parent element might not receive the
+     event. */
+  pointer-events: auto;
+}
+
+#main-section .option > div > .option-label {
+  font-size: 1.1em;
+  font-weight: 600;
+  margin-block-end: 2px;
+}
+
+#main-section .option > div > .option-description {
+  font-size: 1em;
 }
 
-a {
+#main-section a {
   cursor: pointer;
+  font-weight: normal;
 }
 
-#notNowLinkContainer {
-  text-align: end;
-  padding-inline-end: 1em;
+button,
+#onboardingNotNow {
+  margin-block-end: var(--small-margin);
 }
 
-#infoIcon {
-  width: 112px;
-  height: 112px;
-  margin: 0 auto 1em;
-  background-image: url("chrome://branding/content/about-logo.svg");
-  background-size: 100%;
+/* transition from introduction to main */
+#introduction-section.inactive {
+  /* Avoid including this section size */
+  position: fixed;
+  pointer-events: none;
+  animation: fadeout 0.3s forwards;
 }
 
-#infoTitle {
-  font-size: 1.5em;
-  margin: 0;
+#main-section.active {
+  display: flex;
+  animation: fadein 0.3s forwards;
 }
 
-#infoBody {
-  margin: 1em 0;
+ at keyframes fadeout {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    visibility: hidden;
+    opacity: 0;
+  }
 }
 
-#illustration {
-  background: url("quicksuggestOnboarding_illustration.svg") no-repeat center;
-  min-width: 538px;
-  height: 219px;
-  margin: 1em 0 2em;
+ at keyframes fadein {
+  0% {
+    opacity: 0;
+  }
+  100% {
+    pointer-events: initial;
+    opacity: 1;
+  }
 }
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding.html b/browser/components/urlbar/content/quicksuggestOnboarding.html
new file mode 100644
index 0000000000000..615e1261036ad
--- /dev/null
+++ b/browser/components/urlbar/content/quicksuggestOnboarding.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+  <head>
+    <meta http-equiv="Content-Security-Policy"
+          content="default-src chrome:; object-src 'none'">
+    <meta name="referrer" content="no-referrer">
+    <link rel="stylesheet" type="text/css"
+          href="chrome://global/skin/in-content/common.css">
+    <link rel="stylesheet" type="text/css"
+          href="chrome://browser/content/urlbar/quicksuggestOnboarding.css">
+    <link rel="localization" href="branding/brand.ftl">
+    <link rel="localization" href="browser/branding/brandings.ftl"/>
+    <link rel="localization" href="preview/firefoxSuggest.ftl">
+    <script src="chrome://browser/content/urlbar/quicksuggestOnboarding.js"></script>
+  </head>
+  <body role="dialog"
+        aria-labelledby="introduction-title">
+    <section id="introduction-section">
+      <span class="logo" role="presentation"></span>
+      <h1 id="introduction-title"
+          class="title"
+          aria-live="polite"
+          data-l10n-id="firefox-suggest-onboarding-introduction-title"></h1>
+      <button id="onboardingNext"
+              class="primary"
+              tabindex="1"
+              data-l10n-id="firefox-suggest-onboarding-introduction-button"></button>
+      <div class="pager">
+        <span class="current"></span>
+        <span></span>
+      </div>
+    </section>
+    <section id="main-section">
+      <span class="logo" role="presentation"></span>
+      <h1 class="title"
+          aria-live="polite"
+          data-l10n-id="firefox-suggest-onboarding-main-title"></h1>
+      <h2 class="description"
+           tabindex="-1"
+           data-l10n-id="firefox-suggest-onboarding-main-description"></h2>
+      <div class="option accept">
+        <label for="onboardingAccept"></label>
+        <input id="onboardingAccept"
+               type="radio"
+               tabindex="2"
+               name="search-experience"></input>
+        <div>
+          <div class="option-label"
+               data-l10n-id="firefox-suggest-onboarding-main-accept-option-label">
+            <a id="onboardingLearnMore"
+               tabindex="3"
+               data-l10n-name="firefox-suggest-onboarding-learn-more-link"></a>
+          </div>
+          <div class="option-description"
+               data-l10n-id="firefox-suggest-onboarding-main-accept-option-description">
+          </div>
+        </div>
+      </div>
+      <div class="option reject">
+        <label for="onboardingReject"></label>
+        <input id="onboardingReject"
+               type="radio"
+               tabindex="4"
+               name="search-experience"></input>
+        <div>
+          <div class="option-label"
+               data-l10n-id="firefox-suggest-onboarding-main-reject-option-label">
+          </div>
+          <div class="option-description"
+               data-l10n-id="firefox-suggest-onboarding-main-reject-option-description">
+          </div>
+        </div>
+      </div>
+      <button id="onboardingSubmit"
+              class="primary"
+              disabled="true"
+              tabindex="5"
+              data-l10n-id="firefox-suggest-onboarding-main-submit-button"></button>
+      <a id="onboardingNotNow"
+         tabindex="6"
+         data-l10n-id="firefox-suggest-onboarding-main-skip-link"></a>
+      <div class="pager">
+        <span></span>
+        <span class="current"></span>
+      </div>
+    </section>
+  </body>
+</html>
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding.js b/browser/components/urlbar/content/quicksuggestOnboarding.js
index 9f21ef42e5aeb..7c240e69bd847 100644
--- a/browser/components/urlbar/content/quicksuggestOnboarding.js
+++ b/browser/components/urlbar/content/quicksuggestOnboarding.js
@@ -8,56 +8,73 @@ const { ONBOARDING_CHOICE } = ChromeUtils.import(
   "resource:///modules/UrlbarQuickSuggest.jsm"
 );
 
-document.addEventListener("dialogaccept", event => {
-  // dialogaccept is fired when the user presses the enter key even when an
-  // element other than the accept button is focused. If another element is
-  // focused, then peform its action.
-  switch (document.activeElement?.id) {
-    case "onboardingSettingsButton":
-      window.arguments[0].choice = ONBOARDING_CHOICE.SETTINGS;
-      event.preventDefault();
-      window.close();
-      return;
-    case "onboardingNotNow":
-      window.arguments[0].choice = ONBOARDING_CHOICE.NOT_NOW;
-      event.preventDefault();
-      window.close();
-      return;
-    case "onboardingLearnMore":
-      window.arguments[0].choice = ONBOARDING_CHOICE.LEARN_MORE;
-      event.preventDefault();
-      window.close();
-      return;
-  }
+// Number of height pixels to switch to compact mode to avoid showing scrollbars
+// on the non-compact mode. This is based on the natural height of the full-size
+// section height 587px + padding-block-start 32px + padding-block-end 32px +
+// the approximate height of the tab bar 44px.
+const COMPACT_MODE_HEIGHT = 587 + 32 * 2 + 44;
 
-  window.arguments[0].choice = ONBOARDING_CHOICE.ACCEPT;
-});
+document.addEventListener("DOMContentLoaded", () => {
+  addSubmitListener(document.getElementById("onboardingNext"), () => {
+    document.getElementById("introduction-section").classList.add("inactive");
+    document.getElementById("main-section").classList.add("active");
+  });
+  addSubmitListener(document.getElementById("onboardingLearnMore"), () => {
+    window.arguments[0].choice = ONBOARDING_CHOICE.LEARN_MORE;
+    window.close();
+  });
+  addSubmitListener(document.getElementById("onboardingNotNow"), () => {
+    window.arguments[0].choice = ONBOARDING_CHOICE.NOT_NOW;
+    window.close();
+  });
 
-document.addEventListener("dialogextra1", () => {
-  window.arguments[0].choice = ONBOARDING_CHOICE.SETTINGS;
-  window.close();
-});
+  const onboardingSubmit = document.getElementById("onboardingSubmit");
+  const onboardingAccept = document.getElementById("onboardingAccept");
+  const onboardingReject = document.getElementById("onboardingReject");
+  function optionChangeListener() {
+    onboardingSubmit.removeAttribute("disabled");
+    onboardingAccept
+      .closest(".option")
+      .classList.toggle("selected", onboardingAccept.checked);
+    onboardingReject
+      .closest(".option")
+      .classList.toggle("selected", !onboardingAccept.checked);
+  }
+  onboardingAccept.addEventListener("change", optionChangeListener);
+  onboardingReject.addEventListener("change", optionChangeListener);
 
-document.getElementById("onboardingNotNow").addEventListener("click", () => {
-  window.arguments[0].choice = ONBOARDING_CHOICE.NOT_NOW;
-  window.close();
-});
+  function submitListener() {
+    if (!onboardingAccept.checked && !onboardingReject.checked) {
+      return;
+    }
 
-document.getElementById("onboardingLearnMore").addEventListener("click", () => {
-  window.arguments[0].choice = ONBOARDING_CHOICE.LEARN_MORE;
-  window.close();
+    window.arguments[0].choice = onboardingAccept.checked
+      ? ONBOARDING_CHOICE.ACCEPT
+      : ONBOARDING_CHOICE.REJECT;
+    window.close();
+  }
+  addSubmitListener(onboardingSubmit, submitListener);
+  onboardingAccept.addEventListener("keydown", e => {
+    if (e.keyCode == e.DOM_VK_RETURN) {
+      submitListener();
+    }
+  });
+  onboardingReject.addEventListener("keydown", e => {
+    if (e.keyCode == e.DOM_VK_RETURN) {
+      submitListener();
+    }
+  });
+
+  if (window.outerHeight < COMPACT_MODE_HEIGHT) {
+    document.body.classList.add("compact");
+  }
 });
 
-// If we change the system font size while displaying the dialog, problem that
-// components are hidden might happen dependent on the size. To avoid it, we
-// resize dialog explicitly whenever the size of internal components are changed.
-window.addEventListener("load", () => {
-  const resizeObserver = new ResizeObserver(() => {
-    // resizeDialog() does not make window height smaller even if the total
-    // height of internal components is smaller. So, we minimize the window
-    // size once, then prompt to recalculate to be appropriate size.
-    window.resizeBy(0, -window.innerHeight);
-    window.opener.gDialogBox.dialog.resizeDialog();
+function addSubmitListener(element, listener) {
+  element.addEventListener("click", listener);
+  element.addEventListener("keydown", e => {
+    if (e.keyCode == e.DOM_VK_RETURN) {
+      listener();
+    }
   });
-  resizeObserver.observe(document.getElementById("infoContainer"));
-});
+}
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding.xhtml b/browser/components/urlbar/content/quicksuggestOnboarding.xhtml
deleted file mode 100644
index 9cdd9dfdc59fa..0000000000000
--- a/browser/components/urlbar/content/quicksuggestOnboarding.xhtml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0"?>
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<?xml-stylesheet href="chrome://global/skin/global.css"?>
-<?xml-stylesheet href="chrome://global/content/commonDialog.css"?>
-<?xml-stylesheet href="chrome://global/skin/commonDialog.css"?>
-<?xml-stylesheet href="chrome://browser/content/urlbar/quicksuggestOnboarding.css"?>
-
-<window id="quicksuggestOnboardingDialogWindow"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        xmlns:html="http://www.w3.org/1999/xhtml"
-        xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        aria-describedby="infoBody">
-<dialog id="quicksuggestOnboardingDialog"
-        buttons="accept, extra1"
-        defaultButton="accept">
-
-  <linkset>
-    <html:link rel="localization" href="branding/brand.ftl"/>
-  </linkset>
-
-  <!-- The <div> was added in bug 1606617 to workaround bug 1614447 -->
-  <div xmlns="http://www.w3.org/1999/xhtml">
-    <div id="infoContainer">
-      <div id="notNowLinkContainer"><a id="onboardingNotNow" tabindex="4">Not now</a></div>
-      <xul:image id="infoIcon"/>
-      <h2 id="infoTitle">Say hello to smarter suggestions</h2>
-      <xul:description id="infoBody" tabindex="-1">Firefox Suggest uses your city location and search keywords to make contextual suggestions from Firefox and partners, while keeping your privacy in mind. <a id="onboardingLearnMore" tabindex="3">Learn more</a></xul:description>
-      <div id="illustration"/>
-      <div id="infoButtons">
-        <xul:button id="onboardingAcceptButton"
-                    dlgtype="accept"
-                    label="Allow suggestions"
-                    tabindex="1"/>
-        <xul:button id="onboardingSettingsButton"
-                    dlgtype="extra1"
-                    label="Customize in settings"
-                    tabindex="2"/>
-      </div>
-    </div>
-  </div>
-
-  <script src="chrome://browser/content/urlbar/quicksuggestOnboarding.js"/>
-</dialog>
-</window>
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding_illustration.svg b/browser/components/urlbar/content/quicksuggestOnboarding_illustration.svg
deleted file mode 100644
index ca8dd21e51c92..0000000000000
--- a/browser/components/urlbar/content/quicksuggestOnboarding_illustration.svg
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg width="455" height="219" viewBox="0 0 455 219" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g filter="url(#filter0_d)">
-<rect x="43" y="4" width="367" height="207" rx="4" fill="white"/>
-<path d="M80.8651 19.1075C80.5056 18.0614 79.6993 17.3608 78.2227 17.3608C76.6489 17.3608 75.4832 18.2438 75.4832 19.4914C75.4832 20.5086 76.0952 21.19 77.4649 21.5067L78.7084 21.7946C79.4613 21.9674 79.8159 22.3225 79.8159 22.8311C79.8159 23.4645 79.1359 23.9827 78.0673 23.9827C77.1298 23.9827 76.542 23.5845 76.338 22.7927L75.25 23.0614C75.5172 24.3138 76.5615 24.9808 78.0867 24.9808C79.8207 24.9808 81.0011 24.0451 81.0011 22.7735C81.0011 21.7466 80.3502 21.0988 79.0193 20.7774L77.9118  [...]
-<path d="M86.1283 24.9808C87.6438 24.9808 88.7513 24.2322 89.101 23.119L87.9935 22.8119C87.7021 23.5797 87.0269 23.9635 86.1283 23.9635C84.7829 23.9635 83.8551 23.1046 83.8017 21.5259H89.2176V21.0461C89.2176 18.3013 87.5661 17.3608 86.0118 17.3608C83.9911 17.3608 82.6505 18.9347 82.6505 21.1996C82.6505 23.4645 83.9717 24.9808 86.1283 24.9808ZM83.8017 20.547C83.8794 19.4002 84.7003 18.3781 86.0118 18.3781C87.2552 18.3781 88.0518 19.2994 88.0518 20.547H83.8017Z" fill="#15141A" fill-opacity [...]
-<path d="M93.4305 25C94.7322 25 95.4122 24.309 95.6454 23.8292H95.7037V24.8273H96.85V19.9712C96.85 17.6296 95.0431 17.3608 94.091 17.3608C92.9641 17.3608 91.6818 17.7447 91.0989 19.0883L92.187 19.4722C92.4396 18.9347 93.037 18.3589 94.1299 18.3589C95.1839 18.3589 95.7037 18.9107 95.7037 19.856V19.8944C95.7037 20.4415 95.1402 20.3935 93.7802 20.5662C92.3958 20.7438 90.8852 21.0461 90.8852 22.7351C90.8852 24.1747 92.0121 25 93.4305 25ZM93.6053 23.9827C92.6921 23.9827 92.0315 23.5797 92.031 [...]
-<path d="M99.2159 24.8273H100.362V20.1631C100.362 19.1651 101.159 18.4357 102.247 18.4357C102.553 18.4357 102.869 18.4933 102.946 18.5125V17.3608C102.815 17.3512 102.514 17.3417 102.344 17.3417C101.45 17.3417 100.673 17.8407 100.401 18.5701H100.323V17.4568H99.2159V24.8273Z" fill="#15141A" fill-opacity="0.4"/>
-<path d="M107.383 24.9808C109.034 24.9808 110.122 23.9827 110.316 22.6775H109.17C108.956 23.4837 108.276 23.9635 107.383 23.9635C106.023 23.9635 105.148 22.8503 105.148 21.142C105.148 19.4722 106.042 18.3781 107.383 18.3781C108.393 18.3781 108.995 18.9923 109.17 19.6641H110.316C110.122 18.2821 108.937 17.3608 107.363 17.3608C105.343 17.3608 104.002 18.9347 104.002 21.1804C104.002 23.3877 105.284 24.9808 107.383 24.9808Z" fill="#15141A" fill-opacity="0.4"/>
-<path d="M113.412 20.3935C113.412 19.1075 114.243 18.3781 115.374 18.3781C116.453 18.3781 117.104 19.0499 117.104 20.2207V24.8273H118.25V20.144C118.25 18.2486 117.23 17.3608 115.705 17.3608C114.529 17.3608 113.859 17.8455 113.509 18.6084H113.412V15H112.266V24.8273H113.412V20.3935Z" fill="#15141A" fill-opacity="0.4"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M60.6111 21.2507L64.803 25.4425C65.0677 25.7167 65.0639 26.1524 64.7945 26.4219C64.525 26.6914 64.0892 26.6952 63.8151 26.4304L59.6233 22.2386C57.4228 23.919 54.2962 23.6056 52.473 21.5218C50.6499 19.438 50.7545 16.2976 52.7123 14.3398C54.6701 12.3819 57.8106 12.2773 59.8944 14.1005C61.9782 15.9237 62.2916 19.0502 60.6111 21.2507ZM52.6066 18.0768C52.6066 20.199 54.3269 21.9193 56.4491 21.9193C58.5703 21.917 60.2893 20.198 60.2916 18.0768C6 [...]
-<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M394.794 16.5307C394.599 16.3355 394.282 16.3355 394.087 16.5307C393.892 16.726 393.892 17.0426 394.087 17.2378L396.166 19.3174H391.508C391.232 19.3174 391.008 19.5412 391.008 19.8174C391.008 20.0935 391.232 20.3174 391.508 20.3174H396.166L394.087 22.3968C393.892 22.5921 393.892 22.9087 394.087 23.1039C394.282 23.2992 394.599 23.2992 394.794 23.1039L397.715 20.183C397.813 20.0917 397.874 19.9617 397.874 19.8174C397.874 19.673 [...]
-<rect x="46.7695" y="34.4829" width="350.708" height="0.628513" fill="#F0F0F4"/>
-<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M59.9196 123.146L62.9682 126.195C63.1608 126.394 63.158 126.711 62.962 126.907C62.766 127.103 62.4491 127.106 62.2498 126.914L59.2012 123.865C57.6008 125.087 55.3269 124.859 54.001 123.344C52.675 121.828 52.7511 119.544 54.175 118.12C55.5989 116.696 57.8829 116.62 59.3983 117.946C60.9138 119.272 61.1418 121.546 59.9196 123.146ZM54.098 120.838C54.098 122.382 55.3492 123.633 56.8926 123.633C58.4353 123.631 59.6855 122.381 59.6 [...]
-<rect opacity="0.6" x="68.25" y="116" width="88" height="12" rx="2" fill="url(#paint0_linear)"/>
-<rect opacity="0.6" x="68.25" y="139" width="120" height="12" rx="2" fill="url(#paint1_linear)"/>
-<rect opacity="0.6" x="68.25" y="161" width="62" height="12" rx="2" fill="url(#paint2_linear)"/>
-<rect opacity="0.6" x="68.25" y="184" width="112" height="12" rx="2" fill="url(#paint3_linear)"/>
-<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M59.9196 145.773L62.9682 148.822C63.1608 149.021 63.158 149.338 62.962 149.534C62.766 149.73 62.4491 149.733 62.2498 149.54L59.2012 146.491C57.6008 147.714 55.3269 147.486 54.001 145.97C52.675 144.455 52.7511 142.171 54.175 140.747C55.5989 139.323 57.8829 139.247 59.3983 140.573C60.9138 141.899 61.1418 144.173 59.9196 145.773ZM54.098 143.465C54.098 145.008 55.3492 146.259 56.8926 146.259C58.4353 146.258 59.6855 145.007 59.68 [...]
-<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M59.9196 168.399L62.9682 171.448C63.1608 171.647 63.158 171.964 62.962 172.16C62.766 172.356 62.4491 172.359 62.2498 172.166L59.2012 169.118C57.6008 170.34 55.3269 170.112 54.001 168.597C52.675 167.081 52.7511 164.797 54.175 163.373C55.5989 161.949 57.8829 161.873 59.3983 163.199C60.9138 164.525 61.1418 166.799 59.9196 168.399ZM54.098 166.091C54.098 167.635 55.3492 168.886 56.8926 168.886C58.4353 168.884 59.6855 167.634 59.6 [...]
-<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M59.9196 191.025L62.9682 194.074C63.1608 194.273 63.158 194.59 62.962 194.786C62.766 194.982 62.4491 194.985 62.2498 194.792L59.2012 191.744C57.6008 192.966 55.3269 192.738 54.001 191.223C52.675 189.707 52.7511 187.423 54.175 185.999C55.5989 184.575 57.8829 184.499 59.3983 185.825C60.9138 187.151 61.1418 189.425 59.9196 191.025ZM54.098 188.717C54.098 190.261 55.3492 191.512 56.8926 191.512C58.4353 191.51 59.6855 190.26 59.68 [...]
-</g>
-<g filter="url(#filter1_d)">
-<rect x="24" y="39.0596" width="406.5" height="71.0664" rx="4" fill="white"/>
-<path d="M35.25 56.0116H36.0659V53.016H38.9875V52.2965H36.0659V50.0334H39.2902V49.314H35.25V56.0116Z" fill="#15141A"/>
-<path d="M40.5823 56.0116H41.3588V50.9884H40.5823V56.0116ZM40.9771 50.1512C41.2798 50.1512 41.5298 49.9157 41.5298 49.6279C41.5298 49.3401 41.2798 49.1047 40.9771 49.1047C40.6744 49.1047 40.4244 49.3401 40.4244 49.6279C40.4244 49.9157 40.6744 50.1512 40.9771 50.1512Z" fill="#15141A"/>
-<path d="M42.7809 56.0116H43.5573V52.8328C43.5573 52.1526 44.0969 51.6555 44.8339 51.6555C45.0411 51.6555 45.255 51.6948 45.3076 51.7078V50.923C45.2188 50.9164 45.0148 50.9099 44.8997 50.9099C44.2943 50.9099 43.7679 51.25 43.5836 51.7471H43.531V50.9884H42.7809V56.0116Z" fill="#15141A"/>
-<path d="M48.193 56.1163C49.2195 56.1163 49.9696 55.6061 50.2065 54.8474L49.4563 54.6381C49.2589 55.1613 48.8016 55.423 48.193 55.423C47.2816 55.423 46.6532 54.8376 46.617 53.7616H50.2854V53.4346C50.2854 51.564 49.1668 50.923 48.114 50.923C46.7454 50.923 45.8373 51.9956 45.8373 53.5392C45.8373 55.0828 46.7322 56.1163 48.193 56.1163ZM46.617 53.0945C46.6697 52.3129 47.2257 51.6163 48.114 51.6163C48.9563 51.6163 49.4958 52.2442 49.4958 53.0945H46.617Z" fill="#15141A"/>
-<path d="M53.7169 50.9884H52.5852V50.4782C52.5852 49.9811 52.7957 49.7195 53.309 49.7195C53.5327 49.7195 53.6643 49.7718 53.7432 49.798L53.967 49.1308C53.8485 49.0785 53.6116 49 53.23 49C52.5062 49 51.8087 49.4317 51.8087 50.2951V50.9884H50.9928V51.6424H51.8087V56.0116H52.5852V51.6424H53.7169V50.9884Z" fill="#15141A"/>
-<path d="M56.65 56.1163C58.0186 56.1163 58.9398 55.0828 58.9398 53.5262C58.9398 51.9564 58.0186 50.923 56.65 50.923C55.2813 50.923 54.3601 51.9564 54.3601 53.5262C54.3601 55.0828 55.2813 56.1163 56.65 56.1163ZM56.65 55.423C55.6103 55.423 55.1366 54.5334 55.1366 53.5262C55.1366 52.5189 55.6103 51.6163 56.65 51.6163C57.6896 51.6163 58.1634 52.5189 58.1634 53.5262C58.1634 54.5334 57.6896 55.423 56.65 55.423Z" fill="#15141A"/>
-<path d="M60.496 50.9884H59.6011L61.2067 53.5L59.6011 56.0116H60.496L61.7068 54.0625L62.9175 56.0116H63.8124L62.1805 53.5L63.8124 50.9884H62.9175L61.7068 53.0422L60.496 50.9884Z" fill="#15141A"/>
-<path d="M71.3161 50.9884H72.1057C72.0695 49.9778 71.1319 49.2224 69.829 49.2224C68.5393 49.2224 67.526 49.968 67.526 51.093C67.526 51.9956 68.184 52.532 69.2368 52.8328L70.0659 53.0683C70.7765 53.2645 71.4082 53.5131 71.4082 54.1802C71.4082 54.9128 70.6976 55.3968 69.7632 55.3968C68.9605 55.3968 68.2498 55.0436 68.184 54.2849H67.3418C67.4207 55.3837 68.3156 56.1294 69.7632 56.1294C71.3161 56.1294 72.1978 55.2791 72.1978 54.1933C72.1978 52.9375 71.0003 52.532 70.3028 52.3488L69.6185 52.1 [...]
-<path d="M76.6188 53.9578C76.6188 54.8997 75.895 55.3314 75.316 55.3314C74.6711 55.3314 74.2105 54.8605 74.2105 54.1279V50.9884H73.4341V54.1802C73.4341 55.4622 74.1184 56.077 75.0659 56.077C75.8292 56.077 76.3293 55.6715 76.5662 55.1613H76.6188V56.0116H77.3953V50.9884H76.6188V53.9578Z" fill="#15141A"/>
-<path d="M80.8572 58C82.0679 58 83.0418 57.4506 83.0418 56.1555V50.9884H82.2916V51.7863H82.2127C82.0416 51.5247 81.7258 50.923 80.7388 50.923C79.4622 50.923 78.5805 51.9302 78.5805 53.4738C78.5805 55.0436 79.5017 55.9331 80.7256 55.9331C81.7126 55.9331 82.0284 55.3576 82.1995 55.0828H82.2653V56.1032C82.2653 56.9404 81.6731 57.3198 80.8572 57.3198C79.9393 57.3198 79.6169 56.839 79.4096 56.561L78.7911 56.9927C79.1069 57.5193 79.7287 58 80.8572 58ZM80.8309 55.2398C79.857 55.2398 79.3569 54. [...]
-<path d="M86.5029 58C87.7136 58 88.6875 57.4506 88.6875 56.1555V50.9884H87.9373V51.7863H87.8584C87.6873 51.5247 87.3714 50.923 86.3844 50.923C85.1079 50.923 84.2262 51.9302 84.2262 53.4738C84.2262 55.0436 85.1474 55.9331 86.3713 55.9331C87.3583 55.9331 87.6741 55.3576 87.8452 55.0828H87.911V56.1032C87.911 56.9404 87.3188 57.3198 86.5029 57.3198C85.585 57.3198 85.2625 56.839 85.0553 56.561L84.4367 56.9927C84.7526 57.5193 85.3744 58 86.5029 58ZM86.4766 55.2398C85.5027 55.2398 85.0026 54.50 [...]
-<path d="M92.2275 56.1163C93.254 56.1163 94.0041 55.6061 94.241 54.8474L93.4909 54.6381C93.2935 55.1613 92.8362 55.423 92.2275 55.423C91.3162 55.423 90.6878 54.8376 90.6516 53.7616H94.32V53.4346C94.32 51.564 93.2014 50.923 92.1486 50.923C90.7799 50.923 89.8719 51.9956 89.8719 53.5392C89.8719 55.0828 90.7668 56.1163 92.2275 56.1163ZM90.6516 53.0945C90.7042 52.3129 91.2603 51.6163 92.1486 51.6163C92.9908 51.6163 93.5304 52.2442 93.5304 53.0945H90.6516Z" fill="#15141A"/>
-<path d="M99.0807 52.1134C98.8372 51.4004 98.291 50.923 97.2909 50.923C96.2249 50.923 95.4353 51.5247 95.4353 52.375C95.4353 53.0683 95.8498 53.5327 96.7776 53.7485L97.6199 53.9448C98.1298 54.0625 98.37 54.3045 98.37 54.6512C98.37 55.0828 97.9094 55.436 97.1856 55.436C96.5506 55.436 96.1525 55.1646 96.0143 54.625L95.2774 54.8081C95.4583 55.6617 96.1657 56.1163 97.1988 56.1163C98.3733 56.1163 99.1728 55.4786 99.1728 54.6119C99.1728 53.9121 98.7319 53.4706 97.8304 53.2515L97.0803 53.0683C9 [...]
-<path d="M102.539 50.9884H101.46V49.7849H100.684V50.9884H99.9204V51.6424H100.684V54.782C100.684 55.6584 101.394 56.077 102.052 56.077C102.342 56.077 102.526 56.0247 102.631 55.9855L102.473 55.2922C102.408 55.3052 102.302 55.3314 102.131 55.3314C101.789 55.3314 101.46 55.2267 101.46 54.5727V51.6424H102.539V50.9884Z" fill="#15141A"/>
-<rect x="35" y="68" width="32.4659" height="32.4875" rx="2" fill="#F0F0F4"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M53.1801 75C53.5688 75 53.8838 75.3171 53.8838 75.7083V76.4167C53.8838 76.8079 53.5688 77.125 53.1801 77.125C52.7914 77.125 52.4764 76.8079 52.4764 76.4167V75.7083C52.4764 75.3171 52.7914 75 53.1801 75ZM58.1561 77.0747C58.4309 77.3513 58.4309 77.7998 58.1561 78.0764L57.6585 78.5773C57.3837 78.8539 56.9381 78.8539 56.6633 78.5773C56.3885 78.3006 56.3885 77.8521 56.6633 77.5755L57.1609 77.0747C57.4357 76.798 57.8813 76.798 58.1561 77.0747ZM4 [...]
-<rect x="76.25" y="72" width="215" height="12" rx="2" fill="url(#paint5_linear)"/>
-<rect x="76" y="88" width="62" height="6" rx="1" fill="url(#paint6_linear)"/>
-<rect x="357" y="76" width="45" height="6" rx="1" fill="#F0F0F4"/>
-<rect x="405" y="76" width="14" height="6" rx="1" fill="#F0F0F4"/>
-</g>
-<defs>
-<filter id="filter0_d" x="37" y="0" width="379" height="219" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
-<feFlood flood-opacity="0" result="BackgroundImageFix"/>
-<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
-<feOffset dy="2"/>
-<feGaussianBlur stdDeviation="3"/>
-<feColorMatrix type="matrix" values="0 0 0 0 0.227451 0 0 0 0 0.223529 0 0 0 0 0.266667 0 0 0 0.2 0"/>
-<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
-<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
-</filter>
-<filter id="filter1_d" x="0" y="25.0596" width="454.5" height="119.066" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
-<feFlood flood-opacity="0" result="BackgroundImageFix"/>
-<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
-<feOffset dy="10"/>
-<feGaussianBlur stdDeviation="12"/>
-<feColorMatrix type="matrix" values="0 0 0 0 0.227451 0 0 0 0 0.223529 0 0 0 0 0.266667 0 0 0 0.2 0"/>
-<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
-<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
-</filter>
-<linearGradient id="paint0_linear" x1="156.771" y1="128" x2="68.7707" y2="128" gradientUnits="userSpaceOnUse">
-<stop stop-color="#CFCFD8"/>
-<stop offset="0.479167" stop-color="#CFCFD8" stop-opacity="0.3"/>
-<stop offset="0.989583" stop-color="#CFCFD8"/>
-</linearGradient>
-<linearGradient id="paint1_linear" x1="188.25" y1="151" x2="68.25" y2="151" gradientUnits="userSpaceOnUse">
-<stop stop-color="#CFCFD8"/>
-<stop offset="0.525" stop-color="#CFCFD8" stop-opacity="0.3"/>
-<stop offset="1" stop-color="#CFCFD8"/>
-</linearGradient>
-<linearGradient id="paint2_linear" x1="130.25" y1="173" x2="68.25" y2="173" gradientUnits="userSpaceOnUse">
-<stop stop-color="#CFCFD8"/>
-<stop offset="0.516129" stop-color="#CFCFD8" stop-opacity="0.3"/>
-<stop offset="1" stop-color="#CFCFD8"/>
-</linearGradient>
-<linearGradient id="paint3_linear" x1="180.25" y1="196" x2="68.25" y2="196" gradientUnits="userSpaceOnUse">
-<stop stop-color="#CFCFD8"/>
-<stop offset="0.5" stop-color="#CFCFD8" stop-opacity="0.3"/>
-<stop offset="1" stop-color="#CFCFD8"/>
-</linearGradient>
-<linearGradient id="paint4_linear" x1="42.4062" y1="75" x2="60.2171" y2="75" gradientUnits="userSpaceOnUse">
-<stop stop-color="#9059FF"/>
-<stop offset="0.520833" stop-color="#FF4AA2"/>
-<stop offset="1" stop-color="#FFBD4F"/>
-</linearGradient>
-<linearGradient id="paint5_linear" x1="292.394" y1="84" x2="77.3936" y2="84" gradientUnits="userSpaceOnUse">
-<stop stop-color="#CFCFD8"/>
-<stop offset="0.510638" stop-color="#CFCFD8" stop-opacity="0.3"/>
-<stop offset="1" stop-color="#CFCFD8"/>
-</linearGradient>
-<linearGradient id="paint6_linear" x1="138.25" y1="94" x2="76.25" y2="94" gradientUnits="userSpaceOnUse">
-<stop stop-color="#F0F0F4"/>
-<stop offset="0.532258" stop-color="#F0F0F4" stop-opacity="0.3"/>
-<stop offset="1" stop-color="#F0F0F4"/>
-</linearGradient>
-</defs>
-</svg>
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding_magglass.svg b/browser/components/urlbar/content/quicksuggestOnboarding_magglass.svg
new file mode 100644
index 0000000000000..7e9d140e359c5
--- /dev/null
+++ b/browser/components/urlbar/content/quicksuggestOnboarding_magglass.svg
@@ -0,0 +1,34 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public↩
+   - License, v. 2.0. If a copy of the MPL was not distributed with this↩
+   - file, You can obtain one at https://mozilla.org/MPL/2.0/. -->
+<svg width="158" height="115" viewBox="0 0 158 115" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M120.886 24.4352C120.885 24.1852 120.798 23.9433 120.639 23.7507C120.479 23.558 120.258 23.4268 120.013 23.3792C117.928 23.0168 112.136 21.6535 110.178 19.6977C108.223 17.7418 106.859 11.9768 106.5 9.8665C106.452 9.62121 106.32 9.40009 106.128 9.24045C105.936 9.0808 105.694 8.99243 105.444 8.99023V24.4352H120.886Z" fill="#AB71FF"/>
+<path d="M105.525 8.99023C105.27 8.99295 105.025 9.0852 104.831 9.25084C104.637 9.41649 104.507 9.645 104.465 9.89644C104.128 11.9657 102.834 17.6552 100.868 19.7528C98.9015 21.8489 93.1081 23.0893 90.8827 23.4549C90.6355 23.5018 90.4123 23.6333 90.2516 23.8269C90.0908 24.0204 90.0025 24.2639 90.0017 24.5156H105.525V8.99023Z" fill="#9158FF"/>
+<path d="M105.347 24.4375V39.9597C105.598 39.9582 105.841 39.8698 106.035 39.7095C106.228 39.5492 106.36 39.3269 106.409 39.0802C106.77 36.9605 108.139 31.0583 110.106 29.0946C112.075 27.1262 117.87 25.8323 119.966 25.4966C120.217 25.4547 120.445 25.3255 120.611 25.1318C120.776 24.9381 120.868 24.6922 120.87 24.4375H105.347Z" fill="#7542E5"/>
+<path d="M90 24.4375C89.9977 24.6935 90.0883 24.9417 90.2549 25.1362C90.4215 25.3306 90.6529 25.4581 90.9063 25.495C93.0024 25.8323 98.8998 27.1262 100.867 29.093C102.832 31.0583 104.126 36.8549 104.462 39.0519C104.54 39.5783 104.993 39.9644 105.524 39.9581V24.4375H90Z" fill="#592ACB"/>
+<circle cx="73.3988" cy="63.9893" r="50.5" fill="#F9F9FB"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M70.3502 73.7613C62.6751 73.7613 56.4299 67.516 56.4299 59.8408C56.4299 52.1656 62.6751 45.9204 70.3502 45.9204C78.0253 45.9204 84.2705 52.1656 84.2705 59.8408C84.2705 67.516 78.0253 73.7613 70.3502 73.7613ZM100.322 86.6639L84.8051 71.1465C87.2528 68.0238 88.725 64.106 88.725 59.8408C88.725 49.709 80.482 41.4658 70.3502 41.4658C60.2185 41.4658 51.9754 49.709 51.9754 59.8408C51.9754 69.9727 60.2185 78.2158 70.3502 78.2158C74.6154 78.2158 78 [...]
+<path d="M157.809 77.9766C157.816 77.5423 157.667 77.1198 157.39 76.7854C157.113 76.4509 156.725 76.2267 156.297 76.153C152.758 75.5333 142.84 73.1814 139.486 69.8275C136.131 66.4713 133.798 56.5153 133.158 52.9786C133.084 52.5508 132.86 52.1634 132.526 51.8862C132.192 51.6089 131.77 51.4599 131.336 51.466V77.9766H157.809Z" fill="#AB71FF"/>
+<path d="M131.449 51.4689C131.011 51.4628 130.585 51.6144 130.25 51.8959C129.914 52.1775 129.691 52.5703 129.622 53.0027C129.038 56.5439 126.829 66.4753 123.489 69.8159C120.146 73.1565 110.142 75.5117 106.492 76.1872C106.063 76.2612 105.675 76.4857 105.397 76.8204C105.119 77.1551 104.97 77.578 104.976 78.013H131.449V51.4689Z" fill="#7542E5"/>
+<path d="M131.372 77.9379V104.375C131.807 104.381 132.229 104.232 132.563 103.955C132.897 103.677 133.121 103.289 133.195 102.861C133.816 99.2152 136.186 89.2247 139.521 85.8686C142.859 82.5146 152.777 80.3087 156.315 79.7425C157.206 79.5976 157.857 78.8218 157.845 77.9189H131.372V77.9379Z" fill="#7542E5"/>
+<path d="M104.976 77.9346C104.97 78.3695 105.119 78.7924 105.397 79.1271C105.675 79.4618 106.063 79.6863 106.492 79.7603C110.142 80.3266 120.128 82.5536 123.489 85.8942C126.847 89.2348 128.964 99.2944 129.621 102.889C129.691 103.322 129.914 103.715 130.249 103.996C130.585 104.278 131.01 104.43 131.448 104.424V77.9346H104.976Z" fill="#592ACB"/>
+<path d="M62.7863 7.25688C62.7861 7.15433 62.7502 7.05505 62.6849 6.97603C62.6195 6.897 62.5288 6.84313 62.4281 6.82364C61.5726 6.67491 59.1962 6.11558 58.3931 5.31312C57.5907 4.51065 57.0313 2.14528 56.8839 1.27945C56.8641 1.17881 56.8102 1.08808 56.7313 1.02258C56.6523 0.957082 56.5532 0.920822 56.4507 0.919922V7.25688H62.7863Z" fill="#AB71FF"/>
+<path d="M56.4841 0.919922C56.3794 0.921037 56.2785 0.958884 56.199 1.02685C56.1194 1.09481 56.0663 1.18857 56.0489 1.29173C55.9105 2.14076 55.3796 4.47508 54.5733 5.33575C53.7663 6.19576 51.3893 6.70466 50.4762 6.85468C50.3748 6.87391 50.2832 6.92787 50.2173 7.00729C50.1513 7.08671 50.1151 7.18662 50.1148 7.28986H56.4841V0.919922Z" fill="#9158FF"/>
+<path d="M56.4107 7.25781V13.6265C56.5138 13.6258 56.6135 13.5896 56.693 13.5238C56.7724 13.4581 56.8267 13.3668 56.8465 13.2656C56.9946 12.3959 57.5565 9.9743 58.3635 9.1686C59.1711 8.36096 61.5488 7.83008 62.4088 7.69235C62.5119 7.67516 62.6056 7.62216 62.6735 7.54268C62.7414 7.46321 62.7791 7.36233 62.78 7.25781H56.4107Z" fill="#7542E5"/>
+<path d="M50.1141 7.25781C50.1131 7.36286 50.1503 7.46469 50.2187 7.54446C50.287 7.62424 50.382 7.67654 50.4859 7.6917C51.3459 7.83008 53.7656 8.36096 54.5726 9.16795C55.3789 9.9743 55.9098 12.3526 56.0476 13.254C56.0799 13.47 56.2655 13.6284 56.4834 13.6258V7.25781H50.1141Z" fill="#592ACB"/>
+<path d="M49.8614 99.9389C49.861 99.7694 49.8018 99.6053 49.6938 99.4747C49.5858 99.3441 49.4358 99.2551 49.2694 99.2229C47.8555 98.9771 43.9281 98.0527 42.6008 96.7264C41.2746 95.4002 40.3502 91.491 40.1065 90.06C40.0738 89.8937 39.9847 89.7437 39.8543 89.6355C39.7238 89.5272 39.56 89.4673 39.3905 89.4658V99.9389H49.8614Z" fill="#AB71FF"/>
+<path d="M39.4457 89.4658C39.2728 89.4677 39.106 89.5302 38.9746 89.6425C38.8431 89.7549 38.7553 89.9098 38.7265 90.0803C38.4978 91.4835 37.6204 95.3414 36.2878 96.7638C34.9541 98.1852 31.0256 99.0262 29.5166 99.2741C29.349 99.3059 29.1977 99.3951 29.0886 99.5264C28.9796 99.6576 28.9197 99.8227 28.9192 99.9934H39.4457V89.4658Z" fill="#9158FF"/>
+<path d="M39.3244 99.9404V110.466C39.4949 110.465 39.6597 110.405 39.791 110.296C39.9223 110.188 40.0119 110.037 40.0447 109.87C40.2894 108.432 41.2181 104.43 42.5518 103.098C43.8866 101.764 47.8162 100.886 49.2375 100.659C49.4079 100.63 49.5628 100.543 49.675 100.411C49.7872 100.28 49.8495 100.113 49.8509 99.9404H39.3244Z" fill="#7542E5"/>
+<path d="M28.9181 99.9404C28.9165 100.114 28.9779 100.282 29.0909 100.414C29.2039 100.546 29.3608 100.632 29.5326 100.658C30.9539 100.886 34.9529 101.764 36.2866 103.097C37.6193 104.43 38.4967 108.361 38.7243 109.85C38.7777 110.207 39.0844 110.469 39.4446 110.465V99.9404H28.9181Z" fill="#592ACB"/>
+<path d="M29.8933 41.3729C29.896 41.1298 29.8106 40.894 29.6529 40.709C29.4951 40.524 29.2758 40.4024 29.0354 40.3666C27.0422 40.0118 21.4518 38.6895 19.5705 36.7887C17.6891 34.888 16.3475 29.3341 15.9926 27.3238C15.957 27.0833 15.8355 26.8638 15.6505 26.7061C15.4654 26.5483 15.2295 26.463 14.9864 26.4659V41.3729H29.8933Z" fill="#AB71FF"/>
+<path d="M15.0596 26.4668C14.8179 26.468 14.5843 26.5548 14.4005 26.7119C14.2167 26.869 14.0945 27.0861 14.0556 27.3248C13.7179 29.3179 12.4709 34.9072 10.5885 36.7896C8.70712 38.671 3.02431 40.0127 1.0129 40.3675C0.772374 40.4031 0.552898 40.5247 0.395144 40.7097C0.23739 40.8947 0.152054 41.1306 0.154948 41.3738H15.0596V26.4668Z" fill="#7542E5"/>
+<path d="M14.9864 41.3037V56.2084C15.2294 56.2111 15.4652 56.1256 15.6502 55.9679C15.8352 55.8102 15.9568 55.5909 15.9926 55.3505C16.3475 53.3379 17.6891 47.6562 19.5705 45.7737C21.4518 43.8924 27.024 42.6454 29.0354 42.3077C29.2739 42.2686 29.4909 42.1464 29.648 41.9626C29.805 41.7789 29.8919 41.5454 29.8933 41.3037H14.9864Z" fill="#7542E5"/>
+<path d="M0.154877 41.3037C0.156279 41.5454 0.243199 41.7789 0.400235 41.9626C0.557272 42.1464 0.774287 42.2686 1.01283 42.3077C3.04249 42.6454 8.70705 43.8924 10.5884 45.7737C12.4709 47.6562 13.7179 53.3197 14.0556 55.3505C14.1354 55.8445 14.561 56.205 15.0596 56.2084V41.3037H0.154877Z" fill="#592ACB"/>
+<defs>
+<linearGradient id="paint0_linear_4224_71674" x1="51.9754" y1="41.4658" x2="100.975" y2="41.4658" gradientUnits="userSpaceOnUse">
+<stop stop-color="#9059FF"/>
+<stop offset="0.520833" stop-color="#FF4AA2"/>
+<stop offset="1" stop-color="#FFBD4F"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/browser/components/urlbar/content/quicksuggestOnboarding_magglass_animation.svg b/browser/components/urlbar/content/quicksuggestOnboarding_magglass_animation.svg
new file mode 100644
index 0000000000000..e0f9130a3bbcb
--- /dev/null
+++ b/browser/components/urlbar/content/quicksuggestOnboarding_magglass_animation.svg
@@ -0,0 +1,4 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public↩
+   - License, v. 2.0. If a copy of the MPL was not distributed with this↩
+   - file, You can obtain one at https://mozilla.org/MPL/2.0/. -->
+<svg id="euVYRfkX9lv1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 158 115" shape-rendering="geometricPrecision" text-rendering="geometricPrecision"><style><![CDATA[#euVYRfkX9lv2_ts {animation: euVYRfkX9lv2_ts__ts 3000ms linear 1 normal forwards}@keyframes euVYRfkX9lv2_ts__ts { 0% {transform: translate(108.455776px,24.44152px) scale(0.213297,0.213297)} 26.666667% {transform: translate(108.455776px,24.44152px) scale(0.213297,0.213297)} 36.666 [...]
diff --git a/browser/components/urlbar/docs/firefox-suggest-telemetry.rst b/browser/components/urlbar/docs/firefox-suggest-telemetry.rst
index c7391d9b9da0c..609bea662f866 100644
--- a/browser/components/urlbar/docs/firefox-suggest-telemetry.rst
+++ b/browser/components/urlbar/docs/firefox-suggest-telemetry.rst
@@ -211,6 +211,8 @@ The event's objects are the following:
 
 :accept:
   The user accepted the dialog and opted in.
+:reject:
+  The user rejected the dialog and opted out.
 :dismissed_escape_key:
   The user dismissed the dialog by pressing the Escape key. The user remains
   opted out in this case.
@@ -222,9 +224,12 @@ The event's objects are the following:
   The user clicked "Learn more". The user remains opted out in this case.
 :not_now_link:
   The user clicked "Not now". The user remains opted out in this case.
+:not_now:
+  The dialog was dismissed in some way without opting in. This object was
+  removed in Firefox 94.0.
 :settings:
   The user clicked the "Customize" button. The user remains opted out in this
-  case.
+  case. This object was removed in Firefox 96.0.
 
 Changelog
   Firefox 92.0.1
@@ -237,8 +242,14 @@ Changelog
     ``dismissed_other``, ``learn_more``, ``not_now_link``, and ``settings``.
     [Bug 1733687_]
 
+  Firefox 96.0
+    Objects changed to: ``accept``, ``reject``, ``dismissed_escape_key``,
+    ``dismissed_other``, ``learn_more`` and ``not_now_link``.
+    [Bug 1745026_]
+
 .. _1723860: https://bugzilla.mozilla.org/show_bug.cgi?id=1723860
 .. _1733687: https://bugzilla.mozilla.org/show_bug.cgi?id=1733687
+.. _1745026: https://bugzilla.mozilla.org/show_bug.cgi?id=1745026
 
 contextservices.quicksuggest.sponsored_toggled
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -287,6 +298,8 @@ string-valued pref with the following possible values:
   The user has not made a choice (e.g., because the dialog hasn't been shown).
 :accept:
   The user accepted the dialog and opted in.
+:reject:
+  The user rejected the dialog and opted out.
 :dismissed_escape_key:
   The user dismissed the dialog by pressing the Escape key. The user remains
   opted out in this case.
@@ -300,13 +313,17 @@ string-valued pref with the following possible values:
   The user clicked "Not now". The user remains opted out in this case.
 :settings:
   The user clicked the "Customize" button. The user remains opted out in this
-  case.
+  case. This object was removed in Firefox 96.0.
 
 Changelog
   Firefox 94.0
     Introduced. [Bug 1734447_]
 
+  Firefox 96.0
+    Added ``reject`` and removed ``settings``. [Bug 1745026_]
+
 .. _1734447: https://bugzilla.mozilla.org/show_bug.cgi?id=1734447
+.. _1745026: https://bugzilla.mozilla.org/show_bug.cgi?id=1745026
 
 browser.urlbar.quicksuggest.dataCollection.enabled
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/browser/components/urlbar/jar.mn b/browser/components/urlbar/jar.mn
index 29586014c1db4..6ecfbcb668960 100644
--- a/browser/components/urlbar/jar.mn
+++ b/browser/components/urlbar/jar.mn
@@ -4,7 +4,8 @@
 
 browser.jar:
    content/browser/urlbar/preloaded-top-urls.json      (content/preloaded-top-urls.json)
-   content/browser/urlbar/quicksuggestOnboarding.xhtml (content/quicksuggestOnboarding.xhtml)
+   content/browser/urlbar/quicksuggestOnboarding.html (content/quicksuggestOnboarding.html)
    content/browser/urlbar/quicksuggestOnboarding.js    (content/quicksuggestOnboarding.js)
    content/browser/urlbar/quicksuggestOnboarding.css   (content/quicksuggestOnboarding.css)
-   content/browser/urlbar/quicksuggestOnboarding_illustration.svg (content/quicksuggestOnboarding_illustration.svg)
+   content/browser/urlbar/quicksuggestOnboarding_magglass_animation.svg (content/quicksuggestOnboarding_magglass_animation.svg)
+   content/browser/urlbar/quicksuggestOnboarding_magglass.svg (content/quicksuggestOnboarding_magglass.svg)
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js
index f95820d191bfd..211848da8187c 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest.js
@@ -7,10 +7,6 @@
  * Tests browser quick suggestions.
  */
 
-XPCOMUtils.defineLazyModuleGetters(this, {
-  UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm",
-});
-
 const TEST_URL = "http://example.com/quicksuggest";
 
 const TEST_DATA = [
@@ -35,8 +31,6 @@ const TEST_DATA = [
   },
 ];
 
-const SEEN_DIALOG_PREF = "browser.urlbar.quicksuggest.showedOnboardingDialog";
-
 add_task(async function init() {
   await PlacesUtils.history.clear();
   await PlacesUtils.bookmarks.eraseEverything();
@@ -45,61 +39,6 @@ add_task(async function init() {
   await QuickSuggestTestUtils.ensureQuickSuggestInit(TEST_DATA);
 });
 
-add_task(async function test_onboarding() {
-  // Set up prefs so that onboarding will be shown.
-  await SpecialPowers.pushPrefEnv({
-    set: [
-      ["browser.urlbar.quicksuggest.shouldShowOnboardingDialog", true],
-      [
-        "browser.urlbar.quicksuggest.quicksuggest.showedOnboardingDialog",
-        false,
-      ],
-      ["browser.urlbar.quicksuggest.seenRestarts", 0],
-      ["browser.urlbar.quicksuggest.dataCollection.enabled", false],
-      ["browser.urlbar.suggest.quicksuggest.nonsponsored", false],
-      ["browser.urlbar.suggest.quicksuggest.sponsored", false],
-    ],
-  });
-
-  await UrlbarTestUtils.promiseAutocompleteResultPopup({
-    window,
-    value: "fra",
-  });
-  await QuickSuggestTestUtils.assertNoQuickSuggestResults(window);
-  await UrlbarTestUtils.promisePopupClose(window);
-
-  let dialogPromise = BrowserTestUtils.promiseAlertDialog(
-    "accept",
-    "chrome://browser/content/urlbar/quicksuggestOnboarding.xhtml",
-    { isSubDialog: true }
-  ).then(() => info("Saw dialog"));
-  let prefPromise = TestUtils.waitForPrefChange(
-    SEEN_DIALOG_PREF,
-    value => value === true
-  ).then(() => info("Saw pref change"));
-
-  // Simulate 3 restarts. this function is only called by BrowserGlue
-  // on startup, the first restart would be where MR1 was shown then
-  // we will show onboarding the 2nd restart after that.
-  for (let i = 0; i < 3; i++) {
-    info(`Simulating restart ${i + 1}`);
-    await UrlbarQuickSuggest.maybeShowOnboardingDialog();
-  }
-
-  info("Waiting for dialog and pref change");
-  await Promise.all([dialogPromise, prefPromise]);
-
-  await SpecialPowers.popPrefEnv();
-
-  // Clear prefs that are set by virtue of showing and accepting the onboarding.
-  UrlbarPrefs.clear("quicksuggest.shouldShowOnboardingDialog");
-  UrlbarPrefs.clear("quicksuggest.showedOnboardingDialog");
-  UrlbarPrefs.clear("quicksuggest.seenRestarts");
-  UrlbarPrefs.clear("quicksuggest.dataCollection.enabled");
-  UrlbarPrefs.clear("suggest.quicksuggest.nonsponsored");
-  UrlbarPrefs.clear("suggest.quicksuggest.sponsored");
-});
-
 // Tests a sponsored result and keyword highlighting.
 add_task(async function sponsored() {
   await UrlbarTestUtils.promiseAutocompleteResultPopup({
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js
index 081583346b874..40f42748d8b52 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_configuration.js
@@ -43,11 +43,6 @@ add_task(async function test_override_wait_after_n_restarts() {
       quickSuggestShowOnboardingDialogAfterNRestarts: 1,
     },
     callback: async () => {
-      let dialogPromise = BrowserTestUtils.promiseAlertDialog(
-        "accept",
-        "chrome://browser/content/urlbar/quicksuggestOnboarding.xhtml",
-        { isSubDialog: true }
-      ).then(() => info("Saw dialog"));
       let prefPromise = TestUtils.waitForPrefChange(
         "browser.urlbar.quicksuggest.showedOnboardingDialog",
         value => value === true
@@ -56,13 +51,25 @@ add_task(async function test_override_wait_after_n_restarts() {
       // Simulate 2 restarts. this function is only called by BrowserGlue
       // on startup, the first restart would be where MR1 was shown then
       // we will show onboarding the 2nd restart after that.
-      for (let i = 0; i < 2; i++) {
-        info(`Simulating restart ${i + 1}`);
-        await UrlbarQuickSuggest.maybeShowOnboardingDialog();
+      info("Simulating first restart");
+      await UrlbarQuickSuggest.maybeShowOnboardingDialog();
+
+      info("Simulating second restart");
+      const dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
+        null,
+        ONBOARDING_URI,
+        { isSubDialog: true }
+      );
+      const maybeShowPromise = UrlbarQuickSuggest.maybeShowOnboardingDialog();
+      const win = await dialogPromise;
+      if (win.document.readyState != "complete") {
+        await BrowserTestUtils.waitForEvent(win, "load");
       }
+      // Close dialog.
+      EventUtils.synthesizeKey("KEY_Escape");
 
-      info("Waiting for dialog and pref change");
-      await Promise.all([dialogPromise, prefPromise]);
+      info("Waiting for maybeShowPromise and pref change");
+      await Promise.all([maybeShowPromise, prefPromise]);
     },
   });
 
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_onboardingDialog.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_onboardingDialog.js
index be9fcc636d374..41294d83042c4 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_onboardingDialog.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_onboardingDialog.js
@@ -12,9 +12,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
   UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm",
 });
 
-const ONBOARDING_URI =
-  "chrome://browser/content/urlbar/quicksuggestOnboarding.xhtml";
-
 const OTHER_DIALOG_URI = getRootDirectory(gTestPath) + "subdialog.xhtml";
 
 // Default-branch pref values in the offline scenario.
@@ -50,18 +47,47 @@ add_task(async function onboardingShouldNotAppear() {
   UrlbarPrefs.clear("quicksuggest.dataCollection.enabled");
 });
 
-// When the accept button is clicked, the user should be opted in.
+// Test for transition from introduction to main.
+add_task(async function transition() {
+  await doTransitionTest({
+    trigger: win => {
+      info("Find next button");
+      const onboardingNext = win.document.getElementById("onboardingNext");
+      info("Click to transition");
+      onboardingNext.click();
+    },
+  });
+});
+
+// Test for transition from introduction to main by enter key.
+add_task(async function transition_by_enter() {
+  await doTransitionTest({
+    trigger: () => {
+      info("Enter to transition");
+      EventUtils.synthesizeKey("KEY_Enter");
+    },
+  });
+});
+
+// When the accept option is selected, the user should be opted in.
 add_task(async function accept() {
   await doDialogTest({
     callback: async () => {
       let tabCount = gBrowser.tabs.length;
-      let dialogPromise = openDialog("accept");
 
-      info("Calling maybeShowOnboardingDialog");
-      await UrlbarQuickSuggest.maybeShowOnboardingDialog();
+      info("Calling showOnboardingDialog");
+      const { win, maybeShowPromise } = await showOnboardingDialog({
+        skipIntroduction: true,
+      });
+
+      info("Select accept option");
+      win.document.getElementById("onboardingAccept").click();
 
-      info("Waiting for dialog");
-      await dialogPromise;
+      info("Submit");
+      win.document.getElementById("onboardingSubmit").click();
+
+      info("Waiting for maybeShowOnboardingDialog to finish");
+      await maybeShowPromise;
 
       Assert.equal(
         gBrowser.currentURI.spec,
@@ -89,18 +115,25 @@ add_task(async function accept() {
   });
 });
 
-// When the Not Now link is clicked, the user should remain opted out.
-add_task(async function notNow() {
+// When the reject option is selected, the user should be opted out.
+add_task(async function reject() {
   await doDialogTest({
     callback: async () => {
       let tabCount = gBrowser.tabs.length;
-      let dialogPromise = openDialog("onboardingNotNow");
 
-      info("Calling maybeShowOnboardingDialog");
-      await UrlbarQuickSuggest.maybeShowOnboardingDialog();
+      info("Calling showOnboardingDialog");
+      const { win, maybeShowPromise } = await showOnboardingDialog({
+        skipIntroduction: true,
+      });
+
+      info("Select reject option");
+      win.document.getElementById("onboardingReject").click();
 
-      info("Waiting for dialog");
-      await dialogPromise;
+      info("Submit");
+      win.document.getElementById("onboardingSubmit").click();
+
+      info("Waiting for maybeShowOnboardingDialog to finish");
+      await maybeShowPromise;
 
       Assert.equal(
         gBrowser.currentURI.spec,
@@ -109,7 +142,7 @@ add_task(async function notNow() {
       );
       Assert.equal(gBrowser.tabs.length, tabCount, "No news tabs were opened");
     },
-    onboardingDialogChoice: "not_now_link",
+    onboardingDialogChoice: "reject",
     expectedUserBranchPrefs: {
       "quicksuggest.dataCollection.enabled": false,
     },
@@ -122,40 +155,37 @@ add_task(async function notNow() {
       {
         category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
         method: "opt_in_dialog",
-        object: "not_now_link",
+        object: "reject",
       },
     ],
   });
 });
 
-// When the settings button is clicked, the user should remain opted out and
-// about:preferences should load.
-add_task(async function settings() {
+// When the Not Now link is clicked, the user should remain opted out.
+add_task(async function notNow() {
   await doDialogTest({
     callback: async () => {
-      let dialogPromise = openDialog("extra1");
-
-      // about:preferences will load in the current tab since it's about:blank.
-      let loadPromise = BrowserTestUtils.browserLoaded(
-        gBrowser.selectedBrowser
-      ).then(() => info("Saw load"));
+      let tabCount = gBrowser.tabs.length;
 
-      info("Calling maybeShowOnboardingDialog");
-      await UrlbarQuickSuggest.maybeShowOnboardingDialog();
+      info("Calling showOnboardingDialog");
+      const { win, maybeShowPromise } = await showOnboardingDialog({
+        skipIntroduction: true,
+      });
 
-      info("Waiting for dialog");
-      await dialogPromise;
+      info("Click on not now link");
+      win.document.getElementById("onboardingNotNow").click();
 
-      info("Waiting for load");
-      await loadPromise;
+      info("Waiting for maybeShowOnboardingDialog to finish");
+      await maybeShowPromise;
 
       Assert.equal(
         gBrowser.currentURI.spec,
-        "about:preferences#privacy",
-        "Current tab is about:preferences#privacy"
+        "about:blank",
+        "Nothing loaded in the current tab"
       );
+      Assert.equal(gBrowser.tabs.length, tabCount, "No news tabs were opened");
     },
-    onboardingDialogChoice: "settings",
+    onboardingDialogChoice: "not_now_link",
     expectedUserBranchPrefs: {
       "quicksuggest.dataCollection.enabled": false,
     },
@@ -168,7 +198,7 @@ add_task(async function settings() {
       {
         category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
         method: "opt_in_dialog",
-        object: "settings",
+        object: "not_now_link",
       },
     ],
   });
@@ -179,7 +209,6 @@ add_task(async function settings() {
 add_task(async function learnMore() {
   await doDialogTest({
     callback: async () => {
-      let dialogPromise = openDialog("onboardingLearnMore");
       let loadPromise = BrowserTestUtils.waitForNewTab(
         gBrowser,
         QuickSuggestTestUtils.LEARN_MORE_URL
@@ -188,11 +217,16 @@ add_task(async function learnMore() {
         return tab;
       });
 
-      info("Calling maybeShowOnboardingDialog");
-      await UrlbarQuickSuggest.maybeShowOnboardingDialog();
+      info("Calling showOnboardingDialog");
+      const { win, maybeShowPromise } = await showOnboardingDialog({
+        skipIntroduction: true,
+      });
+
+      info("Click on learn more link");
+      win.document.getElementById("onboardingLearnMore").click();
 
-      info("Waiting for dialog");
-      await dialogPromise;
+      info("Waiting for maybeShowOnboardingDialog to finish");
+      await maybeShowPromise;
 
       info("Waiting for new tab");
       let tab = await loadPromise;
@@ -229,7 +263,7 @@ add_task(async function learnMore() {
 add_task(async function escKey_focusInsideDialog() {
   await doFocusTest({
     tabKeyRepeat: 0,
-    expectedFocusID: "onboardingAcceptButton",
+    expectedFocusID: "onboardingNext",
     callback: async () => {
       let tabCount = gBrowser.tabs.length;
       Assert.ok(
@@ -268,7 +302,7 @@ add_task(async function escKey_focusInsideDialog() {
 add_task(async function escKey_focusOutsideDialog() {
   await doFocusTest({
     tabKeyRepeat: 0,
-    expectedFocusID: "onboardingAcceptButton",
+    expectedFocusID: "onboardingNext",
     callback: async () => {
       document.documentElement.focus();
       Assert.ok(
@@ -364,7 +398,7 @@ async function doQueuedEscKeyTest(otherDialogKey) {
 }
 
 // Tests `dismissed_other` by closing the dialog programmatically.
-add_task(async function dismissed_other() {
+add_task(async function dismissed_other_on_introduction() {
   await doDialogTest({
     callback: async () => {
       let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
@@ -402,73 +436,126 @@ add_task(async function dismissed_other() {
   });
 });
 
-// Tests tabbing through the dialog and pressing enter.
-// Tab key count: 0
-// Expected focused element: accept button
-add_task(async function focus_accept() {
-  await doFocusTest({
-    tabKeyRepeat: 0,
-    expectedFocusID: "onboardingAcceptButton",
-    callback: async () => {
-      EventUtils.synthesizeKey("KEY_Enter");
-    },
-    onboardingDialogChoice: "accept",
-    expectedUserBranchPrefs: {
-      "quicksuggest.dataCollection.enabled": true,
-    },
-    telemetryEvents: [
-      {
-        category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
-        method: "data_collect_toggled",
-        object: "enabled",
-      },
-      {
-        category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
-        method: "opt_in_dialog",
-        object: "accept",
-      },
-    ],
+// Tests tabbing through the dialog at initial.
+add_task(async function focus_init_order() {
+  setDialogPrereqPrefs();
+
+  info("Calling showOnboardingDialog");
+  const { win, maybeShowPromise } = await showOnboardingDialog({
+    skipIntroduction: true,
   });
+
+  const order = [
+    "onboardingAccept",
+    "onboardingLearnMore",
+    "onboardingReject",
+    "onboardingNotNow",
+    "onboardingAccept",
+  ];
+
+  for (const next of order) {
+    EventUtils.synthesizeKey("KEY_Tab");
+    Assert.equal(win.document.activeElement.id, next);
+  }
+
+  EventUtils.synthesizeKey("KEY_Escape");
+
+  info("Waiting for maybeShowOnboardingDialog to finish");
+  await maybeShowPromise;
+});
+
+// Tests tabbing through the dialog after selecting accept option.
+add_task(async function focus_order_with_accept_option() {
+  setDialogPrereqPrefs();
+
+  info("Calling showOnboardingDialog");
+  const { win, maybeShowPromise } = await showOnboardingDialog({
+    skipIntroduction: true,
+  });
+
+  info("Select onboardingAccept");
+  EventUtils.synthesizeKey("KEY_Tab");
+  Assert.equal(win.document.activeElement.id, "onboardingAccept");
+  EventUtils.synthesizeKey(" ");
+
+  const order = [
+    "onboardingLearnMore",
+    "onboardingSubmit",
+    "onboardingNotNow",
+    "onboardingAccept",
+  ];
+
+  for (const next of order) {
+    EventUtils.synthesizeKey("KEY_Tab");
+    Assert.equal(win.document.activeElement.id, next);
+  }
+
+  EventUtils.synthesizeKey("KEY_Escape");
+
+  info("Waiting for maybeShowOnboardingDialog to finish");
+  await maybeShowPromise;
+});
+
+// Tests tabbing through the dialog after selecting reject option.
+add_task(async function focus_order_with_reject_option() {
+  setDialogPrereqPrefs();
+
+  info("Calling showOnboardingDialog");
+  const { win, maybeShowPromise } = await showOnboardingDialog({
+    skipIntroduction: true,
+  });
+
+  info("Select onboardingReject");
+  EventUtils.synthesizeKey("KEY_Tab", { repeat: 3 });
+  Assert.equal(win.document.activeElement.id, "onboardingReject");
+  EventUtils.synthesizeKey(" ");
+
+  const order = [
+    "onboardingSubmit",
+    "onboardingNotNow",
+    "onboardingLearnMore",
+    "onboardingReject",
+  ];
+
+  for (const next of order) {
+    EventUtils.synthesizeKey("KEY_Tab");
+    Assert.equal(win.document.activeElement.id, next);
+  }
+
+  EventUtils.synthesizeKey("KEY_Escape");
+
+  info("Waiting for maybeShowOnboardingDialog to finish");
+  await maybeShowPromise;
 });
 
 // Tests tabbing through the dialog and pressing enter.
 // Tab key count: 1
-// Expected focused element: settings button
-add_task(async function focus_settings() {
+// Expected focused element: accept option
+add_task(async function focus_accept() {
   await doFocusTest({
     tabKeyRepeat: 1,
-    expectedFocusID: "onboardingSettingsButton",
+    expectedFocusID: "onboardingAccept",
     callback: async () => {
-      // about:preferences will load in the current tab since it's about:blank.
-      let loadPromise = BrowserTestUtils.browserLoaded(
-        gBrowser.selectedBrowser
-      ).then(() => info("Saw load"));
+      info("Select accept option");
+      EventUtils.synthesizeKey(" ");
 
+      info("Enter to submit");
       EventUtils.synthesizeKey("KEY_Enter");
-
-      info("Waiting for load");
-      await loadPromise;
-
-      Assert.equal(
-        gBrowser.currentURI.spec,
-        "about:preferences#privacy",
-        "Current tab is about:preferences#privacy"
-      );
     },
-    onboardingDialogChoice: "settings",
+    onboardingDialogChoice: "accept",
     expectedUserBranchPrefs: {
-      "quicksuggest.dataCollection.enabled": false,
+      "quicksuggest.dataCollection.enabled": true,
     },
     telemetryEvents: [
       {
         category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
         method: "data_collect_toggled",
-        object: "disabled",
+        object: "enabled",
       },
       {
         category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
         method: "opt_in_dialog",
-        object: "settings",
+        object: "accept",
       },
     ],
   });
@@ -524,10 +611,43 @@ add_task(async function focus_learnMore() {
 
 // Tests tabbing through the dialog and pressing enter.
 // Tab key count: 3
+// Expected focused element: reject option
+add_task(async function focus_reject() {
+  await doFocusTest({
+    tabKeyRepeat: 3,
+    expectedFocusID: "onboardingReject",
+    callback: async () => {
+      info("Select reject option");
+      EventUtils.synthesizeKey(" ");
+
+      info("Enter to submit");
+      EventUtils.synthesizeKey("KEY_Enter");
+    },
+    onboardingDialogChoice: "reject",
+    expectedUserBranchPrefs: {
+      "quicksuggest.dataCollection.enabled": false,
+    },
+    telemetryEvents: [
+      {
+        category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
+        method: "data_collect_toggled",
+        object: "disabled",
+      },
+      {
+        category: QuickSuggestTestUtils.TELEMETRY_EVENT_CATEGORY,
+        method: "opt_in_dialog",
+        object: "reject",
+      },
+    ],
+  });
+});
+
+// Tests tabbing through the dialog and pressing enter. (no option)
+// Tab key count: 4
 // Expected focused element: not now link
 add_task(async function focus_notNow() {
   await doFocusTest({
-    tabKeyRepeat: 3,
+    tabKeyRepeat: 4,
     expectedFocusID: "onboardingNotNow",
     callback: async () => {
       let tabCount = gBrowser.tabs.length;
@@ -559,13 +679,14 @@ add_task(async function focus_notNow() {
 });
 
 // Tests tabbing through the dialog and pressing enter.
-// Tab key count: 4
-// Expected focused element: accept button (wraps around)
+// Expected focused element: accept option (wraps around)
 add_task(async function focus_accept_wraparound() {
   await doFocusTest({
-    tabKeyRepeat: 4,
-    expectedFocusID: "onboardingAcceptButton",
-    callback: async () => {
+    tabKeyRepeat: 5,
+    expectedFocusID: "onboardingAccept",
+    callback: async win => {
+      info("Select accept option");
+      EventUtils.synthesizeKey(" ");
       EventUtils.synthesizeKey("KEY_Enter");
     },
     onboardingDialogChoice: "accept",
@@ -704,27 +825,16 @@ async function doFocusTest({
     expectedUserBranchPrefs,
     telemetryEvents,
     callback: async () => {
-      let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
-        null,
-        ONBOARDING_URI,
-        { isSubDialog: true }
-      );
-
-      let maybeShowPromise = UrlbarQuickSuggest.maybeShowOnboardingDialog();
-
-      let win = await dialogPromise;
-      if (win.document.readyState != "complete") {
-        await BrowserTestUtils.waitForEvent(win, "load");
-      }
+      const { win, maybeShowPromise } = await showOnboardingDialog({
+        skipIntroduction: true,
+      });
 
       let doc = win.document;
 
       Assert.equal(
         doc.activeElement.id,
-        gCanTabMoveFocus
-          ? "onboardingAcceptButton"
-          : "quicksuggestOnboardingDialogWindow",
-        "Accept button is focused initially"
+        "onboardingNext",
+        "onboardingNext is focused initially"
       );
 
       if (tabKeyRepeat) {
@@ -732,20 +842,95 @@ async function doFocusTest({
       }
 
       if (!gCanTabMoveFocus) {
-        expectedFocusID = "quicksuggestOnboardingDialogWindow";
+        expectedFocusID = "onboardingNext";
       }
+
       Assert.equal(
         doc.activeElement.id,
         expectedFocusID,
         "Expected element is focused: " + expectedFocusID
       );
 
-      await callback();
+      await callback(win);
       await maybeShowPromise;
     },
   });
 }
 
+async function doTransitionTest({ trigger }) {
+  setDialogPrereqPrefs();
+
+  info("Calling showOnboardingDialog");
+  const { win, maybeShowPromise } = await showOnboardingDialog();
+
+  info("Check initial status");
+  const introductionSection = win.document.getElementById(
+    "introduction-section"
+  );
+  const mainSection = win.document.getElementById("main-section");
+  Assert.ok(BrowserTestUtils.is_visible(introductionSection));
+  Assert.ok(BrowserTestUtils.is_hidden(mainSection));
+
+  // Trigger the transition.
+  await trigger(win);
+
+  info("Wait for transition");
+  await BrowserTestUtils.waitForCondition(
+    () =>
+      BrowserTestUtils.is_hidden(introductionSection) &&
+      BrowserTestUtils.is_visible(mainSection)
+  );
+  Assert.ok(true, "The transition is finished successfully");
+
+  info("Close the dialog");
+  EventUtils.synthesizeKey("KEY_Escape");
+  await maybeShowPromise;
+}
+
+/**
+ * Show onbaording dialog.
+ *
+ * @param {object}
+ *   skipIntroduction: If true, return dialog with skipping the introduction section.
+ * @returns {object}
+ *   win: window object of the dialog.
+ *   maybeShowPromise: Promise of UrlbarQuickSuggest.maybeShowOnboardingDialog().
+ */
+async function showOnboardingDialog({ skipIntroduction } = {}) {
+  const dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
+    null,
+    ONBOARDING_URI,
+    { isSubDialog: true }
+  );
+
+  const maybeShowPromise = UrlbarQuickSuggest.maybeShowOnboardingDialog();
+
+  const win = await dialogPromise;
+  if (win.document.readyState != "complete") {
+    await BrowserTestUtils.waitForEvent(win, "load");
+  }
+
+  if (!skipIntroduction) {
+    return { win, maybeShowPromise };
+  }
+
+  // Trigger the transition by pressing Enter on the Next button.
+  EventUtils.synthesizeKey("KEY_Enter");
+
+  const introductionSection = win.document.getElementById(
+    "introduction-section"
+  );
+  const mainSection = win.document.getElementById("main-section");
+
+  await BrowserTestUtils.waitForCondition(
+    () =>
+      BrowserTestUtils.is_hidden(introductionSection) &&
+      BrowserTestUtils.is_visible(mainSection)
+  );
+
+  return { win, maybeShowPromise };
+}
+
 /**
  * Sets all the required prefs for showing the onboarding dialog except for the
  * prefs that are set when the dialog is accepted.
@@ -755,13 +940,6 @@ function setDialogPrereqPrefs() {
   UrlbarPrefs.set("quicksuggest.showedOnboardingDialog", false);
 }
 
-async function openDialog(button = undefined) {
-  await BrowserTestUtils.promiseAlertDialog(button, ONBOARDING_URI, {
-    isSubDialog: true,
-  });
-  info("Saw dialog");
-}
-
 /**
  * This is a real hacky way of determining whether the tab key can move focus.
  * Windows and Linux both support it but macOS does not unless full keyboard
@@ -790,18 +968,9 @@ async function canTabMoveFocus() {
   let canMove = false;
   await doDialogTest({
     callback: async () => {
-      let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
-        null,
-        ONBOARDING_URI,
-        { isSubDialog: true }
-      );
-
-      let maybeShowPromise = UrlbarQuickSuggest.maybeShowOnboardingDialog();
-
-      let win = await dialogPromise;
-      if (win.document.readyState != "complete") {
-        await BrowserTestUtils.waitForEvent(win, "load");
-      }
+      const { win, maybeShowPromise } = await showOnboardingDialog({
+        skipIntroduction: true,
+      });
 
       let doc = win.document;
       let { activeElement } = doc;
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/head.js b/browser/components/urlbar/tests/quicksuggest/browser/head.js
index 324c161047eb9..0c4005b04e56c 100644
--- a/browser/components/urlbar/tests/quicksuggest/browser/head.js
+++ b/browser/components/urlbar/tests/quicksuggest/browser/head.js
@@ -13,6 +13,7 @@ Services.scriptloader.loadSubScript(
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.jsm",
+  UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm",
 });
 
 XPCOMUtils.defineLazyGetter(this, "QuickSuggestTestUtils", () => {
@@ -29,3 +30,6 @@ registerCleanupFunction(async () => {
   // to do it within each test.
   await UrlbarTestUtils.promisePopupClose(window);
 });
+
+const ONBOARDING_URI =
+  "chrome://browser/content/urlbar/quicksuggestOnboarding.html";
diff --git a/toolkit/components/telemetry/Events.yaml b/toolkit/components/telemetry/Events.yaml
index 15821c0febe29..fc41f653b08e0 100644
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -3001,7 +3001,7 @@ contextservices.quicksuggest:
       - adw at mozilla.com
     expiry_version: never
   opt_in_dialog:
-    objects: ["accept", "dismissed_escape_key", "dismissed_other", "learn_more", "not_now_link", "settings"]
+    objects: ["accept", "reject", "dismissed_escape_key", "dismissed_other", "learn_more", "not_now_link"]
     release_channel_collection: opt-out
     products:
       - "firefox"
@@ -3009,17 +3009,16 @@ contextservices.quicksuggest:
     description: >
       This is recorded when the user responds to the Firefox Suggest opt-in
       onboarding dialog. 'accept' is recorded when the user accepts the dialog
-      and opts in, 'settings' is recorded when the user clicks in the
-      "Customize" button (the user remains opted out in this case), 'learn_more'
-      is recorded when the user clicks "Learn more" (the user remains opted
-      out), 'not_now_link' is recorded when the user clicks "Not now" (the user
-      remains opted out), 'dismissed_escape_key' is recorded when the user
-      dismisses the dialog by pressing the Escape key (the user remains opted
-      out), 'dismissed_other' is recorded when the dialog is dismissed in some
-      other unknown way, for example when the dialog is replaced with another
-      higher priority dialog like the one shown when quitting the app (the user
-      remains opted out)
-    bug_numbers: [1723860]
+      and opts in, 'settings' is recorded when the user rejects the dialog and
+      opts out, 'learn_more' is recorded when the user clicks "Learn more" (the
+      user remains opted out), 'not_now_link' is recorded when the user clicks
+      "Not now" (the user remains opted out), 'dismissed_escape_key' is recorded
+      when the user dismisses the dialog by pressing the Escape key (the user
+      remains opted out), 'dismissed_other' is recorded when the dialog is
+      dismissed in some other unknown way, for example when the dialog is
+      replaced with another higher priority dialog like the one shown when
+      quitting the app (the user remains opted out)
+    bug_numbers: [1723860, 1745026]
     notification_emails:
       - fx-search at mozilla.com
       - adw at mozilla.com

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tor-commits mailing list