diff --git a/project_browser.libraries.yml b/project_browser.libraries.yml
index 1716ee1fdc00efacd3b257e75f4fb2def7498c55..6915d4612decb5fa776b404513823b63874398a7 100644
--- a/project_browser.libraries.yml
+++ b/project_browser.libraries.yml
@@ -15,6 +15,8 @@ svelte:
     - core/drupal.message
     - core/once
     - project_browser/project_browser
+    # This is included to support dropdown feature.
+    - core/drupal.dropbutton
 
 project_browser:
   css:
diff --git a/sveltejs/public/build/bundle.js b/sveltejs/public/build/bundle.js
index 86164c2f79e64779de5091ca5fa7fb7410e9da42..bd7e99307d6b01a8521602dc50258ba96ddf5183 100644
Binary files a/sveltejs/public/build/bundle.js and b/sveltejs/public/build/bundle.js differ
diff --git a/sveltejs/public/build/bundle.js.map b/sveltejs/public/build/bundle.js.map
index e2cb7317713d25d6380d7e3b939502e3c0dd10e5..f331147d9ab69fc4396616004277cc0bd59f21f3 100644
Binary files a/sveltejs/public/build/bundle.js.map and b/sveltejs/public/build/bundle.js.map differ
diff --git a/sveltejs/src/Project/ActionButton.svelte b/sveltejs/src/Project/ActionButton.svelte
index 01f7429a56b605126b2ba50ebda983e69d2f4d16..9e7c5704e357b8acf34e80cf4cba53d134fdad1f 100644
--- a/sveltejs/src/Project/ActionButton.svelte
+++ b/sveltejs/src/Project/ActionButton.svelte
@@ -1,19 +1,21 @@
 <script>
   import { PACKAGE_MANAGER, MAX_SELECTIONS } from '../constants';
   import { openPopup, getCommandsPopupMessage } from '../popup';
-  import ProjectButtonBase from './ProjectButtonBase.svelte';
   import ProjectStatusIndicator from './ProjectStatusIndicator.svelte';
-  import ProjectIcon from './ProjectIcon.svelte';
   import LoadingEllipsis from './LoadingEllipsis.svelte';
+  import DropButton from './DropButton.svelte';
+  import ProjectButtonBase from './ProjectButtonBase.svelte';
   import {
     processInstallList,
     addToInstallList,
     installList,
     removeFromInstallList,
   } from '../InstallListProcessor';
+  import ProjectIcon from './ProjectIcon.svelte';
 
   // eslint-disable-next-line import/no-mutable-exports,import/prefer-default-export
   export let project;
+  let InstallListFull;
 
   const { Drupal } = window;
   const processMultipleProjects = MAX_SELECTIONS === null || MAX_SELECTIONS > 1;
@@ -52,6 +54,9 @@
     <ProjectStatusIndicator {project} statusText={Drupal.t('Installed')}>
       <ProjectIcon type="installed" />
     </ProjectStatusIndicator>
+    {#if project.tasks.length > 0}
+      <DropButton tasks={project.tasks} />
+    {/if}
   {:else}
     <span>
       {#if PACKAGE_MANAGER}
diff --git a/sveltejs/src/Project/DropButton.svelte b/sveltejs/src/Project/DropButton.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..16451c01772f98f37b1da2879c645acf50435d44
--- /dev/null
+++ b/sveltejs/src/Project/DropButton.svelte
@@ -0,0 +1,76 @@
+<script>
+  // eslint-disable-next-line import/prefer-default-export
+  export let tasks = [];
+
+  // Toggle the dropdown visibility for the clicked drop button
+  const toggleDropdown = (event) => {
+    const wrapper = event.currentTarget.closest('.dropbutton-wrapper');
+    const isOpen = wrapper.classList.contains('open');
+
+    // Close all open dropdowns first
+    document.querySelectorAll('.dropbutton-wrapper.open').forEach((el) => {
+      el.classList.remove('open');
+    });
+
+    if (!isOpen) {
+      wrapper.classList.add('open');
+    }
+  };
+
+  // Handle keydown for closing the dropdown with Escape
+  const handleKeyDown = (event) => {
+    // Query the DOM for getting the only opened dropbutton.
+    const openDropdown = document.querySelector('.dropbutton-wrapper.open');
+    if (!openDropdown) return;
+
+    // If there are no items in the dropdown, exit early
+    if (!openDropdown.querySelectorAll('.secondary-action a').length) return;
+
+    const toggleButton = openDropdown.querySelector('.dropbutton__toggle');
+    if (event.key === 'Escape') {
+      openDropdown.classList.remove('open');
+      toggleButton.focus();
+    }
+  };
+
+  // Close the dropdown if clicked outside
+  const closeDropdownOnOutsideClick = (event) => {
+    document.querySelectorAll('.dropbutton-wrapper.open').forEach((wrapper) => {
+      if (!wrapper.contains(event.target)) {
+        wrapper.classList.remove('open');
+      }
+    });
+  };
+  document.addEventListener('click', closeDropdownOnOutsideClick);
+  document.addEventListener('keydown', handleKeyDown);
+</script>
+
+<div class="dropbutton-wrapper dropbutton-multiple" data-once="dropbutton">
+  <div class="dropbutton-widget">
+    <ul class="dropbutton dropbutton--extrasmall dropbutton--multiple">
+      <li class="dropbutton__item dropbutton-action">
+        <a href={tasks[0].url} on:click={() => {}} class="pb__action_button">
+          {tasks[0].text}
+        </a>
+      </li>
+
+      {#if tasks.length > 1}
+        <li class="dropbutton-toggle">
+          <button
+            type="button"
+            class="dropbutton__toggle"
+            on:click={toggleDropdown}
+          >
+            <span class="visually-hidden">List additional actions</span>
+          </button>
+        </li>
+
+        {#each tasks.slice(1) as task}
+          <li class="dropbutton__item dropbutton-action secondary-action">
+            <a href={task.url}>{task.text}</a>
+          </li>
+        {/each}
+      {/if}
+    </ul>
+  </div>
+</div>
diff --git a/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php b/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php
index a0c09d22ee35e22484f63c6761bbd4852fa0246a..d0a0698622102ec4899a80cf531b22d14ddc9c4f 100644
--- a/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php
+++ b/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php
@@ -4,6 +4,8 @@ declare(strict_types=1);
 
 namespace Drupal\Tests\project_browser\FunctionalJavascript;
 
+use Behat\Mink\Element\NodeElement;
+use Drupal\Core\Extension\ModuleInstallerInterface;
 use Drupal\Core\Recipe\Recipe;
 use Drupal\Core\State\StateInterface;
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
@@ -60,7 +62,7 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
     $this->installState = $install_state;
 
     $this->config('project_browser.admin_settings')
-      ->set('enabled_sources', ['project_browser_test_mock'])
+      ->set('enabled_sources', ['project_browser_test_mock', 'drupal_core', 'recipes'])
       ->set('allow_ui_install', TRUE)
       ->set('max_selections', 1)
       ->save();
@@ -383,4 +385,89 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
     $this->assertTrue($cream_cheese->hasButton('Install Cream cheese on a bagel'));
   }
 
+  /**
+   * Tests the drop button actions for a project.
+   */
+  public function testDropButtonActions(): void {
+    $this->container->get(ModuleInstallerInterface::class)->install([
+      'config_translation',
+      'contact',
+      'content_translation',
+      'help',
+    ]);
+    $this->rebuildContainer();
+
+    $this->drupalGet('admin/modules/browse/recipes');
+    $this->svelteInitHelper('css', '.pb-projects-list');
+
+    $card = $this->waitForProject('Admin theme');
+    $card->pressButton('Install');
+    $this->waitForProjectToBeInstalled($card);
+    // Now assert that the dropdown button does not appear when
+    // we don't have any follow-up actions.
+    $this->assertNull($this->assertSession()->waitForElementVisible('css', '.dropbutton .secondary-action a'));
+
+    $this->drupalGet('admin/modules/browse/drupal_core');
+    $this->svelteInitHelper('css', '.pb-project.pb-project--list');
+    $this->inputSearchField('contact', TRUE);
+    $this->assertElementIsVisible('css', ".search__search-submit")->click();
+    $card = $this->waitForProject('Contact');
+    $card->pressButton('List additional actions');
+    $this->assertChildElementIsVisible($card, 'css', '.dropbutton .secondary-action a');
+
+    $available_actions = [];
+    foreach ($card->findAll('css', '.dropbutton .dropbutton-action a') as $item) {
+      $available_actions[$item->getText()] = $item->getAttribute('href') ?? '';
+    }
+
+    // Assert expected dropdown actions exist and point to the correct places.
+    $this->assertStringEndsWith('/admin/structure/contact', $available_actions['Configure']);
+    $this->assertStringEndsWith('/admin/help/contact', $available_actions['Help']);
+    $this->assertStringContainsString('/project-browser/uninstall/contact', $available_actions['Uninstall']);
+
+    // Ensure that dropdown menus are mutually exclusive.
+    $this->inputSearchField('translation', TRUE);
+    $this->assertElementIsVisible('css', ".search__search-submit")->click();
+    $project1 = $this->waitForProject('Content Translation');
+    $project2 = $this->waitForProject('Configuration Translation');
+
+    // Ensure that an open dropdown closes when you click outside of it.
+    $project1->pressButton('List additional actions');
+    $this->assertChildElementIsVisible($project1, 'css', '.dropbutton .secondary-action a');
+    $project2->click();
+    $this->assertFalse($project1->find('css', '.dropbutton .secondary-action')?->isVisible());
+
+    // Ensure that there can only be one open dropdown at a time.
+    $project2->pressButton('List additional actions');
+    $this->assertChildElementIsVisible($project2, 'css', '.dropbutton .secondary-action a');
+    $project1->pressButton('List additional actions');
+    $this->assertChildElementIsVisible($project1, 'css', '.dropbutton .secondary-action a');
+    $this->assertFalse($project2->find('css', '.dropbutton .secondary-action')?->isVisible());
+
+    // Ensure that we can close an open dropdown by clicking the button again.
+    $project1->pressButton('List additional actions');
+    $this->assertFalse($project1->find('css', '.dropbutton .secondary-action')?->isVisible());
+  }
+
+  /**
+   * Waits for a child of a particular element, to be visible.
+   *
+   * @param \Behat\Mink\Element\NodeElement $parent
+   *   An element that (presumably) contains children.
+   * @param string $selector
+   *   The selector (e.g., `css`, `xpath`, etc.) to use to find a child element.
+   * @param mixed $locator
+   *   The locator to pass to the selector engine.
+   * @param int $timeout
+   *   (optional) How many seconds to wait for the child element to appear.
+   *   Defaults to 10.
+   */
+  private function assertChildElementIsVisible(NodeElement $parent, string $selector, mixed $locator, int $timeout = 10): void {
+    $is_visible = $parent->waitFor(
+      $timeout,
+      fn (NodeElement $parent) => $parent->find($selector, $locator)?->isVisible(),
+    );
+    $this->assertTrue($is_visible);
+  }
+
 }
diff --git a/tests/src/Nightwatch/Tests/keyboardTest.js b/tests/src/Nightwatch/Tests/keyboardTest.js
index b8d83d0c3a78391dd4cc4554b63c53523d51e721..ad2daa59b2ea3ea2b017aaa4c58d923ff9bc9f46 100644
--- a/tests/src/Nightwatch/Tests/keyboardTest.js
+++ b/tests/src/Nightwatch/Tests/keyboardTest.js
@@ -1,6 +1,8 @@
 const delayInMilliseconds = 100;
 const filterKeywordSearch = '#pb-text';
 const filterDropdownSelector = '.pb-filter__multi-dropdown';
+const dropButtonSelector = 'button.dropbutton__toggle';
+const dropButtonItemSelector = 'ul.dropbutton li.secondary-action a';
 
 module.exports = {
   '@tags': ['project_browser'],
@@ -36,6 +38,52 @@ module.exports = {
       return this.actions().sendKeys(browser.Keys.ESCAPE);
     }
     browser.drupalLoginAsAdmin(() => {
+      // We are enabling some modules in order to test the follow-up
+      // actions for some already installed modules in drupal core.
+      browser
+        .drupalRelativeURL('/admin/modules')
+        .click('[name="modules[package_manager][enable]"]')
+        .click('[name="modules[contact][enable]"]')
+        .click('[name="modules[help][enable]"]')
+        .submitForm('input[type="submit"]')
+        .waitForElementVisible(
+          '.system-modules-confirm-form input[value="Continue"]',
+        )
+        .submitForm('input[value="Continue"]')
+        .waitForElementVisible('.system-modules', 10000);
+      browser
+        .drupalRelativeURL('/admin/config/development/project_browser')
+        .waitForElementVisible(
+          '[data-drupal-selector="edit-allow-ui-install"]',
+          delayInMilliseconds,
+        )
+        .click('[data-drupal-selector="edit-allow-ui-install"]')
+
+        // Wait for the select element and enable it
+        .waitForElementVisible(
+          '[data-drupal-selector="edit-enabled-sources-drupal-core-status"]',
+          delayInMilliseconds,
+        )
+        .execute(
+          (selector) => {
+            document.querySelector(selector).removeAttribute('disabled');
+          },
+          ['[data-drupal-selector="edit-enabled-sources-drupal-core-status"]'],
+        )
+
+        .click(
+          '[data-drupal-selector="edit-enabled-sources-drupal-core-status"]',
+        )
+        .click(
+          '[data-drupal-selector="edit-enabled-sources-drupal-core-status"] option[value="enabled"]',
+        )
+
+        // Click the Save Configuration button
+        .waitForElementVisible(
+          '[data-drupal-selector="edit-submit"]',
+          delayInMilliseconds,
+        )
+        .click('[data-drupal-selector="edit-submit"]');
       // Open project browser.
       browser
         .drupalRelativeURL('/admin/modules/browse/project_browser_test_mock')
@@ -169,6 +217,70 @@ module.exports = {
         'Assert that no filter lozenge is shown.',
       );
 
+      browser
+        .drupalRelativeURL('/admin/modules/browse/drupal_core')
+        .waitForElementVisible('h1', delayInMilliseconds)
+        .assert.textContains('h1', 'Browse projects')
+        .waitForElementVisible('#aaa_update_test_title');
+
+      browser
+        .setValue('#pb-text', 'contact')
+        .waitForElementVisible('button.search__search-submit', 5000)
+        .execute(() =>
+          document.querySelector('button.search__search-submit').click(),
+        )
+        .pause(1000)
+        .waitForElementVisible('#contact_title', 1000);
+
+      // Directly focus on the security icon.
+      browser
+        .waitForElementVisible('.pb-project__status-icon-btn', 1000)
+        .execute(
+          (selector) => {
+            const el = document.querySelector(selector);
+            if (el) {
+              el.focus();
+            }
+          },
+          ['.pb-project__status-icon-btn'],
+        );
+      // Navigate to maintenance icon.
+      browser.perform(sendTabKey).pause(1000);
+      // Navigate to installed button.
+      browser.perform(sendTabKey).pause(1000);
+      // Navigate to Installed button.
+      browser.perform(sendTabKey).pause(1000);
+      // Navigate to dropdown button.
+      browser.perform(sendTabKey).pause(1000);
+      assertFocus(dropButtonSelector, 'Assert dropbutton has focus.');
+
+      // Press space to open the dropbutton menu.
+      browser.perform(sendSpaceKey).pause(1000);
+      browser.assert.visible(
+        dropButtonItemSelector,
+        'Assert dropbutton menu is visible.',
+      );
+
+      // Navigate to first dropbutton item using keyboard.
+      browser.perform(sendTabKey).pause(delayInMilliseconds);
+      assertFocus(
+        'ul.dropbutton li.secondary-action a',
+        'Assert first dropbutton item has focus.',
+      );
+      // Navigate to second dropbutton item using keyboard.
+      browser.perform(sendTabKey).pause(delayInMilliseconds);
+      assertFocus(
+        'ul.dropbutton li.secondary-action a',
+        'Assert second dropbutton item has focus.',
+      );
+
+      // Press escape to close the dropbutton menu.
+      browser.perform(sendEscapeKey).pause(1000);
+      assertFocus(
+        dropButtonSelector,
+        'Assert focus returns to dropbutton after closing.',
+      );
+
       // Close out test.
       browser.drupalLogAndEnd({ onlyOnError: false });
     });