How to get the top View of a TabInterface (on desktop)?

165 views
Skip to first unread message

Ramin Halavati

unread,
Jul 18, 2025, 4:27:36 AM7/18/25
to Chromium-dev
Hi,

TLDR:
I have access to the TabInterface of a tab, and need to access the view associated with it. How can I get that?

Details:
I want to register an IPH to a certain tab. Currently the IPH is connected to the kTopContainerElementId of that tab, but the IPH is shown even if the user switches tabs (b/431086811). 
I have the WebContents of the tab and through which I can get TabInterface, but I need an object of the View class, so that I would be able to call views::View::SetProperty(views::kElementIdentifierKey, kMyFeaturesElementId) on it.

Thanks,
Ramin 


Ramin Halavati

unread,
Jul 22, 2025, 4:35:10 AM7/22/25
to Chromium-dev, Dana Fried
@Dana Fried , can you help on this or route it to relevant people?

Dana Fried

unread,
Jul 24, 2025, 12:17:28 PM7/24/25
to Chromium-dev, Ramin Halavati, Dana Fried
Assigning a different ElementId is the wrong approach, and will break other functionality. You should not be dynamically assigning IDs.

Instead, there is the concept of an "element filter" when declaring your IPH. The filter function can consult the controller for your feature and find the relevant tab, or return null if the tab no longer exists.

Conveniently, if you specify kTabElementId, kTabstripElementId, or similar as your starting point, you will be handed all matching elements, so retrieving the relevant view would look something like this:

ui::TrackedElement* GetTargetTab(const ui::ElementTracker::ElementList& elements) {
  if (elements.empty()) {
    return nullptr;
  }
  // This assumes you specified kTabStripElementId as your IPH's target ID, 
  // but you could also use kTabStripRegionElementId and just cast to a different View type.
  TabStrip* tab_strip = views::AsViewClass<TabStrip>(elements[0]->AsA<TrackedElementViews>()->view());
  Tab* found_tab = nullptr;
  // If your controller object is per-browser, you should be able to get the browser from the tabstrip;
  // if it's per-tab, you will be able to get it as you search through the tabs.
  return ElementTrackerViews::GetInstance()->GetElementForView(found_tab);
}

Ramin Halavati

unread,
Jul 25, 2025, 10:57:15 AM7/25/25
to Dana Fried, Chromium-dev
Thank you Dana, that was very helpful.

I tried three solutions with kContentsWebViewElementId, kTabStripElementId, kTopContainerElementId (first two enclosed, third in this CL) .
In all cases I can identify the tab that contains the searchified pdf, but there are the following common issues:
  1. If the user switches the tab, IPH is still shown. Is it because I have not assigned it to a proper element, or should I handle tab change and hiding explicitly?
  2. Does the IPH only attach to the below-middle point of the anchor? If yes, then can we use an element in the content area and expect IPH to show on top of the content area?
Thanks,
Ramin

/*
registry.RegisterFeature(std::move(
...
ContentsWebView::kContentsWebViewElementId,
...
.SetAnchorElementFilter(base::BindRepeating(
[](const ui::ElementTracker::ElementList& elements)
-> ui::TrackedElement* {
if (elements.empty()) {
return nullptr;
}
auto* const browser_view =
views::ElementTrackerViews::GetInstance()
->GetFirstMatchingViewAs<BrowserView>(
kBrowserViewElementId, elements[0]->context());
std::vector<ContentsWebView*> contents_web_views =
browser_view->GetAllVisibleContentsWebViews();
for (auto* contents_web_view : contents_web_views) {
auto* pdf_doc_helper =
pdf::PDFDocumentHelper::MaybeGetForWebContents(
contents_web_view->GetWebContents());
if (pdf_doc_helper && pdf_doc_helper->SearchifyStarted()) {
return views::ElementTrackerViews::GetInstance()
->GetElementForView(contents_web_view);
}
}
return nullptr;
}))));
registry.RegisterFeature(std::move(
....
kTabStripElementId,
....
.SetAnchorElementFilter(base::BindRepeating(
[](const ui::ElementTracker::ElementList& elements)
-> ui::TrackedElement* {
if (elements.empty()) {
return nullptr;
}
auto* tab_strip = views::AsViewClass<TabStrip>(
elements[0]->AsA<views::TrackedElementViews>()->view());
auto* const browser_view =
views::ElementTrackerViews::GetInstance()
->GetFirstMatchingViewAs<BrowserView>(
kBrowserViewElementId, elements[0]->context());
auto* tab_strip_model =
browser_view->browser()->tab_strip_model();
for (int i = 0; i < tab_strip->GetTabCount(); i++) {
auto* pdf_doc_helper =
pdf::PDFDocumentHelper::MaybeGetForWebContents(
tab_strip_model->GetWebContentsAt(i));
if (pdf_doc_helper && pdf_doc_helper->SearchifyStarted()) {
return views::ElementTrackerViews::GetInstance()
->GetElementForView(tab_strip->tab_at(i));
}
}
return nullptr;
}))));
*/

Dana Fried

unread,
Jul 28, 2025, 1:12:48 AM7/28/25
to Ramin Halavati, Chromium-dev
This is reasonable, if a little convoluted. Is there no way to get from a TabStrip to a BrowserView without going through ElementTracker? It seems like a tab strip should know what browser it's in..

As for your questions:

1. Help bubbles start attached to the target view and persist until either:
  • They time out ("toast" style bubbles only)
  • The user interacts with them
  • The anchor view goes away
Therefore, if you want the bubble to go away for some other reason, you must detect and do it manually.
If you created a promo controller associated with the window, you could bypass searching tabs, and the controller can also watch for active tab changes in the browser's TabStripModel.

2. A bubble has an "arrow" which can be set when configuring the IPH. This affects positioning. To answer the second part of this question, a common practice is to target the browser's "top container" and use an arrow of type "none", which causes the IPH to effectively float in the top center of the content pane, just below the toolbar or bookmarks bar (if present).

Hope this helps!

Ramin Halavati

unread,
Jul 29, 2025, 4:30:36 AM7/29/25
to Dana Fried, Chromium-dev
Thank you Dana, that was very helpful. I tried to stay with the common practice and sent you the CL.

Best,
Ramin

Ramin Halavati

Senior Software Engineer

rhal...@google.com
+49 173 2614796


Google Germany GmbH

Erika-Mann-Straße 33

80636 München


Geschäftsführer: Paul Manicle, Liana Sebastian

Registergericht und -nummer: Hamburg, HRB 86891

Sitz der Gesellschaft: Hamburg


Diese E-Mail ist vertraulich. Falls Sie diese fälschlicherweise erhalten haben sollten, leiten Sie diese bitte nicht an jemand anderes weiter, löschen Sie alle Kopien und Anhänge davon und lassen Sie mich bitte wissen, dass die E-Mail an die falsche Person gesendet wurde. 

     

This e-mail is confidential. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it has gone to the wrong person.


Reply all
Reply to author
Forward
0 new messages