diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index e42057e93ac7ffe8833444b091a36a8d4ada34cf..62ed7acb1519416407a8753d1bc9a956276943cf 100644
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -112,6 +112,7 @@ void LLPanelGroup::onOpen(const LLSD& key)
 	if(!key.has("action"))
 	{
 		setGroupID(group_id);
+		getChild<LLAccordionCtrl>("groups_accordion")->expandDefaultTab();
 		return;
 	}
 
@@ -176,11 +177,6 @@ BOOL LLPanelGroup::postBuild()
 	LLPanelGroupTab* panel_notices = findChild<LLPanelGroupTab>("group_notices_tab_panel");
 	LLPanelGroupTab* panel_land = findChild<LLPanelGroupTab>("group_land_tab_panel");
 
-	if (LLAccordionCtrl* accordion_ctrl = getChild<LLAccordionCtrl>("groups_accordion"))
-	{
-		setVisibleCallback(boost::bind(&LLPanelGroup::onVisibilityChange, this, _2, accordion_ctrl));
-	}
-
 	if(panel_general)	mTabs.push_back(panel_general);
 	if(panel_roles)		mTabs.push_back(panel_roles);
 	if(panel_notices)	mTabs.push_back(panel_notices);
@@ -304,14 +300,6 @@ void LLPanelGroup::onBtnCancel()
 	onBackBtnClick();
 }
 
-void LLPanelGroup::onVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl)
-{
-	if (in_visible_chain.asBoolean() && accordion_ctrl != NULL)
-	{
-		accordion_ctrl->expandDefaultTab();
-	}
-}
-
 void LLPanelGroup::changed(LLGroupChange gc)
 {
 	for(std::vector<LLPanelGroupTab* >::iterator it = mTabs.begin();it!=mTabs.end();++it)
diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h
index 86875d2da3743b521487f119a17f298f6b9ad82d..b494c7d403deb7e633aa347abc485e255bb75439 100644
--- a/indra/newview/llpanelgroup.h
+++ b/indra/newview/llpanelgroup.h
@@ -36,7 +36,6 @@ class LLOfferInfo;
 const S32 UPDATE_MEMBERS_PER_FRAME = 500;
 
 // Forward declares
-class LLAccordionCtrl;
 class LLPanelGroupTab;
 class LLTabContainer;
 class LLAgent;
@@ -97,7 +96,6 @@ protected:
 	void onBackBtnClick();
 	void onBtnJoin();
 	void onBtnCancel();
-	void onVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl);
 
 	static void onBtnApply(void*);
 	static void onBtnRefresh(void*);
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 7af3ad9896df80a923313645db64e975507336f3..1d32b5894851b528930d08aa20238d2046a33357 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -244,9 +244,7 @@ void LLSideTrayTab::toggleTabDocked()
 	LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name);
 	if (!floater_tab) return;
 
-	LLFloaterReg::toggleInstance("side_bar_tab", tab_name);
-
-	bool docking = !LLFloater::isShown(floater_tab);
+	bool docking = LLFloater::isShown(floater_tab);
 
 	// Hide the "Tear Off" button when a tab gets undocked
 	// and show "Dock" button instead.
@@ -261,6 +259,10 @@ void LLSideTrayTab::toggleTabDocked()
 	{
 		undock(floater_tab);
 	}
+
+	// Open/close the floater *after* we reparent the tab panel,
+	// so that it doesn't receive redundant visibility change notifications.
+	LLFloaterReg::toggleInstance("side_bar_tab", tab_name);
 }
 
 void LLSideTrayTab::dock()
@@ -282,7 +284,7 @@ void LLSideTrayTab::dock()
 
 	if (side_tray->getCollapsed())
 	{
-		side_tray->expandSideBar();
+		side_tray->expandSideBar(false);
 	}
 }
 
@@ -291,6 +293,10 @@ void LLSideTrayTab::undock(LLFloater* floater_tab)
 	LLSideTray* side_tray = getSideTray();
 	if (!side_tray) return;
 
+	// Remember whether the tab have been active before detaching
+	// because removeTab() will change active tab.
+	bool was_active = side_tray->getActiveTab() == this;
+
 	// Remove the tab from Side Tray's tabs list.
 	// We have to do it despite removing the tab from Side Tray's child view tree
 	// by addChild(). Otherwise the tab could be accessed by the pointer in LLSideTray::mTabs.
@@ -300,7 +306,12 @@ void LLSideTrayTab::undock(LLFloater* floater_tab)
 		return;
 	}
 
-	setVisible(true); // *HACK: restore visibility after being hidden by LLSideTray::selectTabByName().
+	// If we're undocking while side tray is collapsed we need to explicitly show the panel.
+	if (!getVisible())
+	{
+		setVisible(true);
+	}
+
 	floater_tab->addChild(this);
 	floater_tab->setTitle(mTabTitle);
 
@@ -334,7 +345,7 @@ void LLSideTrayTab::undock(LLFloater* floater_tab)
 		side_tray->collapseSideBar();
 	}
 
-	if (side_tray->getActiveTab() != this)
+	if (!was_active)
 	{
 		// When a tab other then current active tab is detached from Side Tray
 		// onOpen() should be called as tab visibility is changed.
@@ -618,8 +629,9 @@ bool LLSideTray::selectTabByIndex(size_t index)
 	return selectTabByName(sidebar_tab->getName());
 }
 
-bool LLSideTray::selectTabByName	(const std::string& name)
+bool LLSideTray::selectTabByName(const std::string& name, bool keep_prev_visible)
 {
+	LLSideTrayTab* tab_to_keep_visible = NULL;
 	LLSideTrayTab* new_tab = getTab(name);
 	if (!new_tab) return false;
 
@@ -630,6 +642,8 @@ bool LLSideTray::selectTabByName	(const std::string& name)
 	//deselect old tab
 	if (mActiveTab)
 	{
+		// Keep previously active tab visible if requested.
+		if (keep_prev_visible) tab_to_keep_visible = mActiveTab;
 		toggleTabButton(mActiveTab);
 	}
 
@@ -650,9 +664,17 @@ bool LLSideTray::selectTabByName	(const std::string& name)
 	for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it)
 	{
 		LLSideTrayTab* sidebar_tab = *child_it;
+
+		bool vis = sidebar_tab == mActiveTab;
+
+		// Force keeping the tab visible if requested.
+		vis |= sidebar_tab == tab_to_keep_visible;
+
 		// When the last tab gets detached, for a short moment the "Toggle Sidebar" pseudo-tab
 		// is shown. So, to avoid the flicker we make sure it never gets visible.
-		sidebar_tab->setVisible(sidebar_tab == mActiveTab && (*child_it)->getName() != "sidebar_openclose");
+		vis &= (*child_it)->getName() != "sidebar_openclose";
+
+		sidebar_tab->setVisible(vis);
 	}
 	return true;
 }
@@ -741,7 +763,7 @@ bool LLSideTray::removeTab(LLSideTrayTab* tab)
 	{
 		child_vector_iter_t next_tab_it =
 				(tab_it < (mTabs.end() - 1)) ? tab_it + 1 : mTabs.begin();
-		selectTabByName((*next_tab_it)->getName());
+		selectTabByName((*next_tab_it)->getName(), true); // Don't hide the tab being removed.
 	}
 
 	// Remove the tab.
@@ -1016,7 +1038,7 @@ void LLSideTray::collapseSideBar()
 	setFocus( FALSE );
 }
 
-void LLSideTray::expandSideBar()
+void LLSideTray::expandSideBar(bool open_active)
 {
 	mCollapsed = false;
 	LLSideTrayTab* openclose_tab = getTab("sidebar_openclose");
@@ -1024,8 +1046,11 @@ void LLSideTray::expandSideBar()
 	{
 		mCollapseButton->setImageOverlay( openclose_tab->mImageSelected );
 	}
-	LLSD key;//empty
-	mActiveTab->onOpen(key);
+
+	if (open_active)
+	{
+		mActiveTab->onOpen(LLSD());
+	}
 
 	reflectCollapseChange();
 
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 248def8e3d506a7eb395734d66d413b4002329e8..4e79007c13d624454348e43d3f8394664a5154ba 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -76,9 +76,12 @@ public:
 	// interface functions
 	    
 	/**
-     * Select tab with specific name and set it active    
-     */
-	bool 		selectTabByName	(const std::string& name);
+	 * Select tab with specific name and set it active
+	 *
+	 * @param name				Tab to switch to.
+	 * @param keep_prev_visible	Whether to keep the previously selected tab visible.
+	 */
+	bool 		selectTabByName	(const std::string& name, bool keep_prev_visible = false);
 	
 	/**
      * Select tab with specific index and set it active    
@@ -119,8 +122,10 @@ public:
     
 	/*
      * expand SideBar
+     *
+     * @param open_active Whether to call onOpen() for the active tab.
      */
-	void		expandSideBar	();
+	void		expandSideBar(bool open_active = true);
 
 
 	/**