diff --git a/docs/en/framework/ui/mvc-razor-pages/branding.md b/docs/en/framework/ui/mvc-razor-pages/branding.md
index e8e9309ff8..9c9f5c6a37 100644
--- a/docs/en/framework/ui/mvc-razor-pages/branding.md
+++ b/docs/en/framework/ui/mvc-razor-pages/branding.md
@@ -43,8 +43,45 @@ The result will be like shown below:
* `LogoUrl`: A URL to show the application logo.
* `LogoReverseUrl`: A URL to show the application logo on a reverse color theme (dark, for example).
+ABP's built-in MVC themes resolve the branding URLs for the current request. `/logo.png`, `logo.png` and `~/logo.png` are treated as application relative URLs and include the `PathBase` of the request, so they keep working when the application is deployed to a non-root path, like an IIS virtual directory. Absolute HTTP(S) URLs, like `https://cdn.example.com/logo.png`, and protocol relative URLs, like `//cdn.example.com/logo.png`, are returned unchanged. `null` and white space values are treated as not set.
+
+If you render a branding URL in a custom MVC theme or view, resolve it with `Url.ResolveBrandingUrl(...)`.
+
> **Tip**: `IBrandingProvider` is used in every page refresh. For a multi-tenant application, you can return a tenant specific application name to customize it per tenant.
+## IBrandingLogoProvider
+
+Some theme areas need a compact logo, like a collapsed menu. To provide one, make the same branding provider implement both `IBrandingProvider` and `IBrandingLogoProvider`. `DefaultBrandingProvider` implements both, so a derived provider only overrides the icon properties:
+
+````csharp
+using Volo.Abp.Ui.Branding;
+using Volo.Abp.DependencyInjection;
+
+namespace MyProject.Web
+{
+ [Dependency(ReplaceServices = true)]
+ public class MyProjectBrandingProvider : DefaultBrandingProvider
+ {
+ public override string AppName => "Book Store";
+
+ public override string LogoUrl => "/logo.png";
+
+ public override string LogoIconUrl => "/logo-icon.png";
+ }
+}
+````
+
+`IBrandingLogoProvider` has the following properties:
+
+* `LogoIconUrl`: A URL to show the compact application logo.
+* `LogoIconReverseUrl`: A URL to show the compact application logo on a reverse color theme.
+
+Both properties return `null` by default and follow the same URL rules as `LogoUrl`.
+
+The active theme decides whether and where to use the compact logo. The LeptonX MVC theme enables its compact branding when `LogoIconUrl` is not empty: it uses the compact logo instead of the full logo in its branding areas and shows `AppName` next to it where there is room for both. Dark and dim styles use `LogoIconReverseUrl` and fall back to `LogoIconUrl` when it is not set. Themes that don't support `IBrandingLogoProvider` ignore these properties.
+
+> This URL resolution and the compact logo apply to the ASP.NET Core MVC / Razor Pages themes. The Blazor themes handle branding on their own.
+
## Overriding the Branding Area
You can see the [UI Customization Guide](customization-user-interface.md) to learn how you can replace the branding area with a custom view component.
diff --git a/docs/en/ui-themes/lepton-x/mvc.md b/docs/en/ui-themes/lepton-x/mvc.md
index 392af280fe..e52e1a91c8 100644
--- a/docs/en/ui-themes/lepton-x/mvc.md
+++ b/docs/en/ui-themes/lepton-x/mvc.md
@@ -261,6 +261,8 @@ General Settings can be replaced with following files.
Application name and logo can be customized by using the `IBrandingProvider` service. See [Razor Pages: Branding](../../framework/ui/mvc-razor-pages/branding.md) for more information.
+When the branding provider also provides a `LogoIconUrl`, LeptonX switches to its compact branding: the branding areas show the logo icon instead of the full logo and render the application name next to it. Dark and dim styles use `LogoIconReverseUrl` and fall back to `LogoIconUrl`.
+
If you need to replace the component, you can follow the steps below.
* The **main header branding component page (.cshtml file)** is defined in the `Themes/LeptonX/Components/Common/MainHeaderBranding/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**.
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs
new file mode 100644
index 0000000000..f652dac543
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Branding/UrlHelperBrandingExtensions.cs
@@ -0,0 +1,40 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Branding;
+
+public static class UrlHelperBrandingExtensions
+{
+ ///
+ /// Resolves a branding url of for the current request.
+ /// "logo.svg", "/logo.svg" and "~/logo.svg" all mean the same application relative url and keep working
+ /// under a non-root .
+ /// External urls ("http://", "https://" and "//host/") are returned as they are.
+ /// Returns null when is null or white space.
+ ///
+ public static string? ResolveBrandingUrl(this IUrlHelper urlHelper, string? url)
+ {
+ if (url.IsNullOrWhiteSpace())
+ {
+ return null;
+ }
+
+ if (IsExternalUrl(url!))
+ {
+ return url;
+ }
+
+ var applicationRelativeUrl = url!.StartsWith("~/", StringComparison.Ordinal)
+ ? url
+ : "~/" + url.TrimStart('/');
+
+ return urlHelper.Content(applicationRelativeUrl);
+ }
+
+ private static bool IsExternalUrl(string url)
+ {
+ return url.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
+ || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
+ || url.StartsWith("//", StringComparison.Ordinal);
+ }
+}
diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs
new file mode 100644
index 0000000000..6661f17c73
--- /dev/null
+++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/BrandingProviderLogoExtensions.cs
@@ -0,0 +1,20 @@
+namespace Volo.Abp.Ui.Branding;
+
+public static class BrandingProviderLogoExtensions
+{
+ ///
+ /// Returns the compact logo of the branding provider on white background when available; otherwise, null.
+ ///
+ public static string? GetLogoIconUrlOrNull(this IBrandingProvider brandingProvider)
+ {
+ return (brandingProvider as IBrandingLogoProvider)?.LogoIconUrl;
+ }
+
+ ///
+ /// Returns the compact logo of the branding provider on dark background when available; otherwise, null.
+ ///
+ public static string? GetLogoIconReverseUrlOrNull(this IBrandingProvider brandingProvider)
+ {
+ return (brandingProvider as IBrandingLogoProvider)?.LogoIconReverseUrl;
+ }
+}
diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs
index fcb1a7545e..aa386c593e 100644
--- a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs
+++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/DefaultBrandingProvider.cs
@@ -2,11 +2,15 @@
namespace Volo.Abp.Ui.Branding;
-public class DefaultBrandingProvider : IBrandingProvider, ITransientDependency
+public class DefaultBrandingProvider : IBrandingProvider, IBrandingLogoProvider, ITransientDependency
{
public virtual string AppName => "MyApplication";
public virtual string? LogoUrl => null;
public virtual string? LogoReverseUrl => null;
+
+ public virtual string? LogoIconUrl => null;
+
+ public virtual string? LogoIconReverseUrl => null;
}
diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs
new file mode 100644
index 0000000000..4cb38cd3a8
--- /dev/null
+++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/Branding/IBrandingLogoProvider.cs
@@ -0,0 +1,18 @@
+namespace Volo.Abp.Ui.Branding;
+
+///
+/// Optionally implemented by an to provide a compact logo,
+/// used where the full logo does not fit, like a collapsed menu.
+///
+public interface IBrandingLogoProvider
+{
+ ///
+ /// Compact logo on white background
+ ///
+ string? LogoIconUrl { get; }
+
+ ///
+ /// Compact logo on dark background
+ ///
+ string? LogoIconReverseUrl { get; }
+}
diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml
index 04a4f81c71..fb15426730 100644
--- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml
+++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml
@@ -1,9 +1,10 @@
@using Volo.Abp.Ui.Branding
+@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Branding
@inject IBrandingProvider BrandingProvider
@if (!BrandingProvider.LogoUrl.IsNullOrWhiteSpace())
{
-
+
}
@BrandingProvider.AppName
diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
index 5dc1619ec8..75c57ec834 100644
--- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
+++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
@@ -12,6 +12,7 @@
@using Volo.Abp.MultiTenancy
@using Volo.Abp.Localization
@using Volo.Abp.Ui.Branding
+@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Branding
@using Volo.Abp.Ui.LayoutHooks
@inject IBrandingProvider BrandingProvider
@inject IOptions MultiTenancyOptions
@@ -64,7 +65,7 @@
-

+
@BrandingProvider.AppName
@if (MultiTenancyOptions.Value.IsEnabled &&