Repository: dotnetcore/BootstrapBlazor (2025-08-21T05:14:09Z)

Issue:
feat(Tooltip): support manual trigger
### Is there an existing issue for this?

- [x] I have searched the existing issues

### Is your feature request related to a problem? Please describe the problem.

I have to show the tooltip programmatically, I can not find a way to do that in `BootstrapBlazor`.


### Describe the solution you'd like


according to the bootstrap's tooltip doc(https://getbootstrap.com/docs/5.3/components/tooltips/)

```
How tooltip is triggered: click, hover, focus, manual. You may pass multiple triggers; separate them with a space. 'manual' indicates that the tooltip will be triggered programmatically via the .tooltip('show'), .tooltip('hide') and .tooltip('toggle') methods; this value cannot be combined with any other trigger. 'hover' on its own will result in tooltips that cannot be triggered via the keyboard, and should only be used if alternative methods for conveying the same information for keyboard users is present.
```

### Additional context

_No response_


Discussion:
@ice6 Thank you for contacting us. We will give feedback later.
@ice6 thank you for submit issue. actually `Tooltip` component `Trigger` parameter is `string` type. support `maunal` option. later i will  update our documentation
@ArgoZhang thank you, remember to add show & hide(or autohide with delay time after shown) the tooltip programmatically example. 
@ice6 please feel fres try `v9.9.3-beta03` `Tooltip` `Popover` both support trigger `manual` value



Patch:
diff --git a/src/BootstrapBlazor.Server/Components/Components/TooltipContent.razor b/src/BootstrapBlazor.Server/Components/Components/TooltipContent.razor
new file mode 100644
index 00000000000..90ee795c511
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/TooltipContent.razor
@@ -0,0 +1,1 @@
+﻿<i class="fa-solid fa-flag" style="cursor: pointer;" @onclick="ToggleShow" />
diff --git a/src/BootstrapBlazor.Server/Components/Components/TooltipContent.razor.cs b/src/BootstrapBlazor.Server/Components/Components/TooltipContent.razor.cs
new file mode 100644
index 00000000000..3b453dc86ca
--- /dev/null
+++ b/src/BootstrapBlazor.Server/Components/Components/TooltipContent.razor.cs
@@ -0,0 +1,25 @@
+﻿// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License
+// See the LICENSE file in the project root for more information.
+// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
+
+namespace BootstrapBlazor.Server.Components.Components;
+
+/// <summary>
+/// TooltipContent 组件用于显示 Tooltip 的内容
+/// </summary>
+public partial class TooltipContent
+{
+    [CascadingParameter]
+    private Tooltip? Tooltip { get; set; }
+
+    private async Task ToggleShow()
+    {
+        if (Tooltip == null)
+        {
+            return;
+        }
+
+        await Tooltip.Toggle();
+    }
+}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor b/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor
index 3196a4cc376..90a8c2f40dc 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor
+++ b/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor
@@ -66,4 +66,19 @@
     </Popover>
 </DemoBlock>
 
+<DemoBlock Title="@Localizer["PopoversManualTitle"]"
+           Introduction="@Localizer["PopoversManualIntro"]"
+           Name="Manual">
+    <section ignore>
+        <ul class="ul-demo">
+            <li>@((MarkupString)Localizer["PopoversManualDescLI1"].Value)</li>
+            <li>@((MarkupString)Localizer["PopoversManualDescLI2"].Value)</li>
+        </ul>
+    </section>
+    <Popover Title="@Title" Content="@Content" IsHtml="true" Trigger="manual" @ref="_popover">
+        <i class="fa-solid fa-flag" style="cursor: pointer;"></i>
+    </Popover>
+    <Button Text="Trigger" OnClickWithoutRender="ToggleShow"></Button>
+</DemoBlock>
+
 <AttributeTable Items="@GetAttributes()" />
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor.cs
index 40c694123cd..c9a32d7ca07 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/Popovers.razor.cs
@@ -18,6 +18,16 @@ public sealed partial class Popovers
 
     private string? _templateTitle;
 
+    private Popover? _popover;
+
+    private async Task ToggleShow()
+    {
+        if (_popover != null)
+        {
+            await _popover.Toggle();
+        }
+    }
+
     /// <summary>
     /// <inheritdoc/>
     /// </summary>
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor b/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor
index 73434013139..0f4bfad44a5 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor
+++ b/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor
@@ -88,4 +88,19 @@
     </Tooltip>
 </DemoBlock>
 
+<DemoBlock Title="@Localizer["TooltipsManualTitle"]"
+           Introduction="@Localizer["TooltipsManualIntro"]"
+           Name="Manual">
+    <section ignore>
+        <ul class="ul-demo">
+            <li>@((MarkupString)Localizer["TooltipsManualDescLI1"].Value)</li>
+            <li>@((MarkupString)Localizer["TooltipsManualDescLI2"].Value)</li>
+        </ul>
+    </section>
+    <Tooltip Title="Manual trigger tooltip" Trigger="manual" @ref="_tooltip">
+        <TooltipContent></TooltipContent>
+    </Tooltip>
+    <Button Text="Trigger" OnClickWithoutRender="ToggleShow"></Button>
+</DemoBlock>
+
 <AttributeTable Items="@GetAttributes()" />
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor.cs
index f6392484fa3..ca0274194e4 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/Tooltips.razor.cs
@@ -20,6 +20,16 @@ public partial class Tooltips
 
     private static string HtmlString => "This is <a href=\"www.blazor.zone\">Blazor</a> tooltip";
 
+    private Tooltip? _tooltip;
+
+    private async Task ToggleShow()
+    {
+        if (_tooltip != null)
+        {
+            await _tooltip.Toggle();
+        }
+    }
+
     /// <summary>
     /// 获得属性方法
     /// </summary>
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index 78596d35a69..3f262a8381b 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -108,7 +108,11 @@
     "TooltipsCustomClassIntro": "Set the custom style by setting the <code>CustomClass</code> parameter",
     "BootstrapTooltipIntro": "Try to make a new component that is more comfortable to use, you can use it early, the name of the component may be changed later",
     "BootstrapTooltipTips1": "Wrap other components or <code>HTML</code> elements through <code>BootstrapTooltip</code> so that the wrapped object has the function of <code>Tooltip</code>",
-    "BootstrapTooltipTips2": "In this example, an icon is wrapped by <code>BootstrapTooltip</code>. When the mouse moves over the icon, the default <code>Tooltip</code> is displayed, which is easier and faster to use."
+    "BootstrapTooltipTips2": "In this example, an icon is wrapped by <code>BootstrapTooltip</code>. When the mouse moves over the icon, the default <code>Tooltip</code> is displayed, which is easier and faster to use.",
+    "TooltipsManualTitle": "Manual",
+    "TooltipsManualIntro": "Use code to control the tooltip state by setting <code>Trigger=\"manual\"</code>",
+    "TooltipsManualDescLI1": "The child component uses the cascade parameters to get the <code>Tooltip</code> instance and then calls its methods <code>Show</code> <code>Hide</code> <code>Toggle</code>",
+    "TooltipsManualDescLI2": "Get the Tooltip instance through <code>@ref</code> and call its instances method"
   },
   "BootstrapBlazor.Server.Components.Samples.Toasts": {
     "ToastsTitle": "Toast Lightweight Popup",
@@ -348,7 +352,11 @@
     "PopoversCssClassTitle": "custom style",
     "PopoversCssClassIntro": "Customize the pop-up window by setting the <code>Popover</code> parameter <code>CssClass</code>",
     "PopoversCssClassDescription": "set up <code>Popover</code> parameter <code>CssClass=\"custom-popover\"</code> make custom styles",
-    "PopoversCssClassButtonText": "Click to activate/deactivate"
+    "PopoversCssClassButtonText": "Click to activate/deactivate",
+    "PopoversManualTitle": "Manual",
+    "PopoversManualIntro": "Use code to control the popover state by setting <code>Trigger=\"manual\"</code>",
+    "PopoversManualDescLI1": "The child component uses the cascade parameters to get the <code>Popover</code> instance and then calls its methods <code>Show</code> <code>Hide</code> <code>Toggle</code>",
+    "PopoversManualDescLI2": "Get the Popover instance through <code>@ref</code> and call its instances method"
   },
   "BootstrapBlazor.Server.Components.Samples.Progress": {
     "ProgressTitle": "Progress progress bar",
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index 7d7e6e3498a..53c6acca4c0 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -108,7 +108,11 @@
     "TooltipsCustomClassIntro": "通过设置 <code>CustomClass</code> 参数进行自定义样式设置",
     "BootstrapTooltipIntro": "尝试新做一个用起来比较舒服的组件，可尝鲜使用，后期组件名字可能会更改",
     "BootstrapTooltipTips1": "通过 <code>BootstrapTooltip</code> 对其他组件或者 <code>HTML</code> 元素进行包裹，使其被包裹对象具有 <code>Tooltip</code> 功能",
-    "BootstrapTooltipTips2": "本例中通过 <code>BootstrapTooltip</code> 包裹一个图标，鼠标移动到图标上时，显示预设 <code>Tooltip</code> 使用更简单快捷"
+    "BootstrapTooltipTips2": "本例中通过 <code>BootstrapTooltip</code> 包裹一个图标，鼠标移动到图标上时，显示预设 <code>Tooltip</code> 使用更简单快捷",
+    "TooltipsManualTitle": "手动控制状态",
+    "TooltipsManualIntro": "通过设置 <code>Trigger=\"manual\"</code> 使用代码控制提示栏状态",
+    "TooltipsManualDescLI1": "子组件使用级联参数得到 <code>Tooltip</code> 实例，然后调用其相应方法 <code>Show</code> <code>Hide</code> <code>Toggle</code>",
+    "TooltipsManualDescLI2": "通过 <code>@ref</code> 获得 <code>Tooltip</code> 实例调用其对应方法"
   },
   "BootstrapBlazor.Server.Components.Samples.Toasts": {
     "ToastsTitle": "Toast 轻量弹窗",
@@ -348,7 +352,11 @@
     "PopoversCssClassTitle": "自定义样式",
     "PopoversCssClassIntro": "通过设置 <code>Popover</code> 参数 <code>CssClass</code> 对弹窗进行自定义样式",
     "PopoversCssClassDescription": "设置 <code>Popover</code> 参数 <code>CssClass=\"custom-popover\"</code> 进行自定义样式",
-    "PopoversCssClassButtonText": "Click 激活/关闭"
+    "PopoversCssClassButtonText": "Click 激活/关闭",
+    "PopoversManualTitle": "手动控制状态",
+    "PopoversManualIntro": "通过设置 <code>Trigger=\"manual\"</code> 使用代码控制提示栏状态",
+    "PopoversManualDescLI1": "子组件使用级联参数得到 <code>Popover</code> 实例，然后调用其相应方法 <code>Show</code> <code>Hide</code> <code>Toggle</code>",
+    "PopoversManualDescLI2": "通过 <code>@ref</code> 获得 <code>Popover</code> 实例调用其对应方法"
   },
   "BootstrapBlazor.Server.Components.Samples.Progress": {
     "ProgressTitle": "Progress 进度条",
diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj
index 12f00e1294c..b444c814a51 100644
--- a/src/BootstrapBlazor/BootstrapBlazor.csproj
+++ b/src/BootstrapBlazor/BootstrapBlazor.csproj
@@ -1,7 +1,7 @@
 ﻿<Project Sdk="Microsoft.NET.Sdk.Razor">
 
   <PropertyGroup>
-    <Version>9.9.3-beta02</Version>
+    <Version>9.9.3-beta03</Version>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/src/BootstrapBlazor/Components/Popover/Popover.razor b/src/BootstrapBlazor/Components/Popover/Popover.razor
index b2751275abc..318ac5215ef 100644
--- a/src/BootstrapBlazor/Components/Popover/Popover.razor
+++ b/src/BootstrapBlazor/Components/Popover/Popover.razor
@@ -4,7 +4,8 @@
 
 <span @attributes="@AdditionalAttributes" class="@ClassString" tabindex="0" id="@Id"
       data-bs-toggle="popover" data-bs-original-title="@Title"
-      data-bs-selector="@Selector" data-bs-placement="@PlacementString" data-bs-custom-class="@CustomClassString"
+      data-bs-selector="@Selector" data-bs-placement="@PlacementString"
+      data-bs-custom-class="@CustomClassString"
       data-bs-trigger="@Trigger" data-bs-delay="@Delay"
       data-bs-offset="@Offset" data-bs-fallbackPlacements="@FallbackPlacementsString"
       data-bs-html="@HtmlString" data-bs-sanitize="@SanitizeString">
diff --git a/src/BootstrapBlazor/Components/Popover/Popover.razor.cs b/src/BootstrapBlazor/Components/Popover/Popover.razor.cs
index c30c51a9328..32cdc4d947c 100644
--- a/src/BootstrapBlazor/Components/Popover/Popover.razor.cs
+++ b/src/BootstrapBlazor/Components/Popover/Popover.razor.cs
@@ -30,10 +30,11 @@ public partial class Popover
 
     private string? _lastContent;
 
-    /// <summary>
-    /// <inheritdoc/>
-    /// </summary>
-    protected override string? CustomClassString => CssBuilder.Default(CustomClass)
+    private string? ClassString => CssBuilder.Default("bb-popover")
+        .AddClassFromAttributes(AdditionalAttributes)
+        .Build();
+
+    private string? CustomClassString => CssBuilder.Default(CustomClass)
         .AddClass("shadow", ShowShadow)
         .Build();
 
diff --git a/src/BootstrapBlazor/Components/Popover/Popover.razor.js b/src/BootstrapBlazor/Components/Popover/Popover.razor.js
index 6dd1bfd2339..5994ab60cbd 100644
--- a/src/BootstrapBlazor/Components/Popover/Popover.razor.js
+++ b/src/BootstrapBlazor/Components/Popover/Popover.razor.js
@@ -9,6 +9,42 @@ export function init(id, options) {
     }
 }
 
+export function show(id, delay) {
+    const el = document.getElementById(id)
+    if (el) {
+        const pop = bootstrap.Popover.getInstance(el);
+        if (pop) {
+            setTimeout(() => {
+                pop.show();
+            }, delay || 0);
+        }
+    }
+}
+
+export function hide(id, delay) {
+    const el = document.getElementById(id)
+    if (el) {
+        const pop = bootstrap.Popover.getInstance(el);
+        if (pop) {
+            setTimeout(() => {
+                pop.hide();
+            }, delay || 0);
+        }
+    }
+}
+
+export function toggle(id, delay) {
+    const el = document.getElementById(id)
+    if (el) {
+        const pop = bootstrap.Popover.getInstance(el);
+        if (pop) {
+            setTimeout(() => {
+                pop.toggle();
+            }, delay || 0);
+        }
+    }
+}
+
 export function dispose(id) {
     const el = document.getElementById(id)
     if (el) {
diff --git a/src/BootstrapBlazor/Components/Tooltip/ITooltip.cs b/src/BootstrapBlazor/Components/Tooltip/ITooltip.cs
index 8fcbcbdf2dd..8ffda90c231 100644
--- a/src/BootstrapBlazor/Components/Tooltip/ITooltip.cs
+++ b/src/BootstrapBlazor/Components/Tooltip/ITooltip.cs
@@ -26,8 +26,9 @@ public interface ITooltip
     bool IsHtml { get; set; }
 
     /// <summary>
-    /// 获得/设置 触发方式 可组合 click focus hover 默认为 focus hover
+    /// 获得/设置 触发方式 可组合 click focus hover manual 默认为 focus hover
     /// </summary>
+    /// <remarks>设置 manual 时，请使用 <see cref="Tooltip"/> 组件实例方法 <see cref="Tooltip.Show(int?)"/> <see cref="Tooltip.Hide(int?)"/> <see cref="Tooltip.Toggle(int?)"/> 对弹窗状态进行控制</remarks>
     string? Trigger { get; set; }
 
     /// <summary>
@@ -39,6 +40,7 @@ public interface ITooltip
     /// <summary>
     /// 获得/设置 显示隐藏延时 默认 null
     /// </summary>
+    /// <remarks>Delay showing and hiding the tooltip (ms)—doesn’t apply to manual trigger type. If a number is supplied, delay is applied to both hide/show. Object structure is: delay: { "show": 500, "hide": 100 }.</remarks>
     string? Delay { get; set; }
 
     /// <summary>
diff --git a/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor b/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor
index f3ccbc1af45..2ff453a0a18 100644
--- a/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor
+++ b/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor
@@ -4,7 +4,7 @@
 
 <span @attributes="@AdditionalAttributes" class="@ClassString" tabindex="0" id="@Id"
       data-bs-toggle="tooltip" data-bs-original-title="@Title"
-      data-bs-selector="@Selector" data-bs-placement="@PlacementString" data-bs-custom-class="@CustomClassString"
+      data-bs-selector="@Selector" data-bs-placement="@PlacementString" data-bs-custom-class="@CustomClass"
       data-bs-trigger="@Trigger" data-bs-delay="@Delay"
       data-bs-offset="@Offset" data-bs-fallbackPlacements="@FallbackPlacementsString"
       data-bs-html="@HtmlString" data-bs-sanitize="@SanitizeString">
diff --git a/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.cs b/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.cs
index 5999ea3625e..bcba585290e 100644
--- a/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.cs
+++ b/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.cs
@@ -25,10 +25,7 @@ public partial class Tooltip : ITooltip
     /// </summary>
     protected string? HtmlString => IsHtml ? "true" : null;
 
-    /// <summary>
-    /// component class
-    /// </summary>
-    protected string? ClassString => CssBuilder.Default()
+    private string? ClassString => CssBuilder.Default("bb-tooltip")
         .AddClassFromAttributes(AdditionalAttributes)
         .Build();
 
@@ -50,7 +47,7 @@ public partial class Tooltip : ITooltip
     public string? Selector { get; set; }
 
     /// <summary>
-    /// 获得/设置 显示内容
+    /// <inheritdoc/>
     /// </summary>
     [Parameter]
     public string? Title { get; set; }
@@ -62,7 +59,7 @@ public partial class Tooltip : ITooltip
     public Func<Task<string>>? GetTitleCallback { get; set; }
 
     /// <summary>
-    /// 获得/设置 显示文字是否为 Html 默认为 false
+    /// <inheritdoc/>
     /// </summary>
     [Parameter]
     public bool IsHtml { get; set; }
@@ -74,7 +71,7 @@ public partial class Tooltip : ITooltip
     public bool Sanitize { get; set; } = true;
 
     /// <summary>
-    /// 获得/设置 位置 默认为 Placement.Top
+    /// <inheritdoc/>
     /// </summary>
     [Parameter]
     public Placement Placement { get; set; } = Placement.Top;
@@ -92,14 +89,13 @@ public partial class Tooltip : ITooltip
     public string? Offset { get; set; }
 
     /// <summary>
-    /// 获得/设置 自定义样式 默认 null
+    /// <inheritdoc/>
     /// </summary>
-    /// <remarks>由 data-bs-custom-class 实现</remarks>
     [Parameter]
     public string? CustomClass { get; set; }
 
     /// <summary>
-    /// 获得/设置 触发方式 可组合 click focus hover 默认为 focus hover
+    /// <inheritdoc/>
     /// </summary>
     [Parameter]
     public string? Trigger { get; set; }
@@ -110,11 +106,6 @@ public partial class Tooltip : ITooltip
     [Parameter]
     public RenderFragment? ChildContent { get; set; }
 
-    /// <summary>
-    /// 获得 CustomClass 字符串
-    /// </summary>
-    protected virtual string? CustomClassString => CustomClass;
-
     /// <summary>
     /// <inheritdoc/>
     /// </summary>
@@ -156,4 +147,25 @@ public void SetParameters(string title, Placement placement = Placement.Auto, st
         if (!string.IsNullOrEmpty(offset)) Offset = offset;
         StateHasChanged();
     }
+
+    /// <summary>
+    /// 显示 Tooltip 弹窗方法
+    /// </summary>
+    /// <param name="delay">延时指定毫秒后显示弹窗 默认 null 不延时</param>
+    /// <returns></returns>
+    public Task Show(int? delay = null) => InvokeVoidAsync("show", Id, delay);
+
+    /// <summary>
+    /// 关闭 Tooltip 弹窗方法
+    /// </summary>
+    /// <param name="delay">延时指定毫秒后关闭弹窗 默认 null 不延时</param>
+    /// <returns></returns>
+    public Task Hide(int? delay = null) => InvokeVoidAsync("hide", Id, delay);
+
+    /// <summary>
+    /// 切换 Tooltip 弹窗当前状态方法
+    /// </summary>
+    /// <param name="delay">延时指定毫秒后切换弹窗方法 默认 null 不延时</param>
+    /// <returns></returns>
+    public Task Toggle(int? delay = null) => InvokeVoidAsync("toggle", Id, delay);
 }
diff --git a/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.js b/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.js
index b7591813b75..47f34c789c6 100644
--- a/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.js
+++ b/src/BootstrapBlazor/Components/Tooltip/Tooltip.razor.js
@@ -20,6 +20,33 @@ export function init(id) {
     }
 }
 
+export function show(id, delay) {
+    const tip = Data.get(id)
+    const { tooltip } = tip;
+
+    setTimeout(() => {
+        tooltip.show();
+    }, delay || 0);
+}
+
+export function hide(id, delay) {
+    const tip = Data.get(id)
+    const { tooltip } = tip;
+
+    setTimeout(() => {
+        tooltip.hide();
+    }, delay || 0);
+}
+
+export function toggle(id, delay) {
+    const tip = Data.get(id)
+    const { tooltip } = tip;
+
+    setTimeout(() => {
+        tooltip.toggle();
+    }, delay || 0);
+}
+
 export function dispose(id) {
     const tip = Data.get(id)
     Data.remove(id)


Test patch:
diff --git a/test/UnitTest/Components/TooltipTest.cs b/test/UnitTest/Components/TooltipTest.cs
index d62219e83a7..3b346362122 100644
--- a/test/UnitTest/Components/TooltipTest.cs
+++ b/test/UnitTest/Components/TooltipTest.cs
@@ -176,4 +176,17 @@ public void FallbackPlacements_Ok()
         });
         cut.Contains("data-bs-fallbackPlacements=\"top,left\"");
     }
+
+    [Fact]
+    public async Task Toggle_Ok()
+    {
+        var cut = Context.RenderComponent<Tooltip>(pb =>
+        {
+            pb.Add(a => a.Title, "test_tooltip");
+            pb.Add(a => a.Trigger, "manual");
+        });
+        await cut.InvokeAsync(() => cut.Instance.Show());
+        await cut.InvokeAsync(() => cut.Instance.Hide());
+        await cut.InvokeAsync(() => cut.Instance.Toggle());
+    }
 }