diff --git a/src/Plugin/ProjectBrowserSource/Recipes.php b/src/Plugin/ProjectBrowserSource/Recipes.php
index bf9b5a1e61b49b119449ab8267af44a642e8ecea..cdffcbe4affe75afda46f58e67e1a92c034d27a1 100644
--- a/src/Plugin/ProjectBrowserSource/Recipes.php
+++ b/src/Plugin/ProjectBrowserSource/Recipes.php
@@ -122,6 +122,10 @@ final class Recipes extends ProjectBrowserSourceBase {
           url: $url ?? NULL,
         );
       }
+      // Sort the $projects array by the 'title' property in ascending order.
+      usort($projects, function (Project $a, Project $b) {
+        return strcasecmp($a->title, $b->title);
+      });
       $this->cacheBin->set($this->getPluginId(), $projects);
     }
 
diff --git a/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php b/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php
index 58e87f9f09096fcb322ad247d3be533c508911ca..c4168321bbcc1ce7456dea491a595d42b215c391 100644
--- a/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php
+++ b/tests/src/FunctionalJavascript/ProjectBrowserInstallerUiTest.php
@@ -154,6 +154,10 @@ class ProjectBrowserInstallerUiTest extends WebDriverTestBase {
 
     // If we reload, the installation status should be remembered.
     $this->getSession()->reload();
+    $this->inputSearchField('image', TRUE);
+    $submit_button = $assert_session->waitForElementVisible('css', ".search__search-submit");
+    $this->assertNotEmpty($submit_button);
+    $submit_button->click();
     $card = $assert_session->waitForElementVisible('css', '.pb-project:contains("Image media type")');
     $this->assertNotEmpty($card);
     $assert_installed($card);
diff --git a/tests/src/Kernel/RecipesSourceTest.php b/tests/src/Kernel/RecipesSourceTest.php
index 32f993ffd5eec73ef3462fcfbddf7cbeb9101a92..cd8818901be7caa2cb868b592367aedb8fa50123 100644
--- a/tests/src/Kernel/RecipesSourceTest.php
+++ b/tests/src/Kernel/RecipesSourceTest.php
@@ -162,4 +162,56 @@ class RecipesSourceTest extends KernelTestBase {
     $this->assertSame($expected_recipe_names, $found_recipe_names);
   }
 
+  /**
+   * Tests sorting of discovered recipes by case-insensitive name.
+   */
+  public function testRecipeSortingByRecipeName(): void {
+    $this->setSetting('extension_discovery_scan_tests', TRUE);
+
+    /** @var \Drupal\project_browser\Plugin\ProjectBrowserSourceInterface $source */
+    $source = $this->container->get(ProjectBrowserSourceManager::class)
+      ->createInstance('recipes');
+
+    // Generate fake recipes with varying case names.
+    $generated_recipes = [
+      'deltaRecipe' => '{"name": "drupal/delta_recipe"}',
+      'betaRecipe' => '{"name": "drupal/beta_recipe"}',
+      'AlphaRecipe' => '{"name": "drupal/alpha_recipe"}',
+      'GammaRecipe' => '{"name": "drupal/gamma_recipe"}',
+    ];
+
+    $installed_recipes_dir = uniqid(FileSystem::getOsTemporaryDirectory() . '/');
+    $file_system = new SymfonyFilesystem();
+    $file_system->mkdir($installed_recipes_dir);
+
+    foreach ($generated_recipes as $recipe_name => $composer_json_content) {
+      $recipe_dir = $installed_recipes_dir . '/' . $recipe_name;
+      $file_system->mkdir($recipe_dir);
+      file_put_contents($recipe_dir . '/composer.json', $composer_json_content);
+      file_put_contents($recipe_dir . '/recipe.yml', "name: $recipe_name");
+    }
+
+    $this->setSetting('project_browser_recipe_directories', [$installed_recipes_dir]);
+
+    // Fetch discovered recipes.
+    /** @var \Drupal\project_browser\ProjectBrowser\ProjectsResultsPage $projects */
+    $projects = $this->container->get(ProjectBrowserSourceManager::class)
+      ->createInstance('recipes')
+      ->getProjects();
+    $found_recipes = array_column($projects->list, 'title');
+
+    $generated_recipe_titles = array_keys($generated_recipes);
+    // Filter the discovered recipe titles to include only those that
+    // were generated during the test.
+    $found_generated_titles = array_values(array_intersect($found_recipes, $generated_recipe_titles));
+
+    // Sort the expected titles using case-insensitive sorting.
+    usort($generated_recipe_titles, 'strcasecmp');
+
+    $this->assertSame($generated_recipe_titles, $found_generated_titles);
+
+    // Clean up.
+    $file_system->remove($installed_recipes_dir);
+  }
+
 }