diff --git a/public/app/features/dashboard-scene/scene/VariableControls.test.tsx b/public/app/features/dashboard-scene/scene/VariableControls.test.tsx
new file mode 100644
index 00000000000..c65639edfa6
--- /dev/null
+++ b/public/app/features/dashboard-scene/scene/VariableControls.test.tsx
@@ -0,0 +1,84 @@
+import { render, screen } from '@testing-library/react';
+
+import { VariableHide } from '@grafana/data';
+import { SceneGridLayout, SceneVariable, SceneVariableSet, ScopesVariable, TextBoxVariable } from '@grafana/scenes';
+
+import { DashboardScene } from './DashboardScene';
+import { VariableControls } from './VariableControls';
+import { DefaultGridLayoutManager } from './layout-default/DefaultGridLayoutManager';
+
+jest.mock('@grafana/runtime', () => {
+ const runtime = jest.requireActual('@grafana/runtime');
+ return {
+ ...runtime,
+ config: {
+ ...runtime.config,
+ featureToggles: {
+ dashboardNewLayouts: true,
+ },
+ },
+ };
+});
+
+describe('VariableControls', () => {
+ it('should not render scopes variable', () => {
+ const variables = [new ScopesVariable({})];
+ const dashboard = buildScene(variables);
+ dashboard.activate();
+
+ render();
+
+ expect(screen.queryByText('__scopes')).not.toBeInTheDocument();
+ });
+
+ it('should not render regular hidden variables', () => {
+ const hiddenVariable = new TextBoxVariable({
+ name: 'HiddenVar',
+ hide: VariableHide.hideVariable,
+ });
+ const variables = [hiddenVariable];
+ const dashboard = buildScene(variables);
+ dashboard.activate();
+
+ render();
+
+ expect(screen.queryByText('HiddenVar')).not.toBeInTheDocument();
+ });
+
+ it('should render regular hidden variables in edit mode', async () => {
+ const hiddenVariable = new TextBoxVariable({
+ name: 'HiddenVar',
+ hide: VariableHide.hideVariable,
+ });
+ const variables = [hiddenVariable];
+ const dashboard = buildScene(variables);
+ dashboard.activate();
+
+ dashboard.setState({ isEditing: true });
+ render();
+
+ expect(await screen.findByText('HiddenVar')).toBeInTheDocument();
+ });
+
+ it('should not render variables hidden in controls menu in edit mode', async () => {
+ const dashboard = buildScene([new TextBoxVariable({ name: 'TextVarControls', hide: VariableHide.inControlsMenu })]);
+ dashboard.activate();
+
+ dashboard.setState({ isEditing: true });
+ render();
+
+ expect(screen.queryByText('TextVarControls')).not.toBeInTheDocument();
+ });
+});
+
+function buildScene(variables: SceneVariable[] = []) {
+ const dashboard = new DashboardScene({
+ $variables: new SceneVariableSet({ variables }),
+ body: new DefaultGridLayoutManager({
+ grid: new SceneGridLayout({
+ children: [],
+ }),
+ }),
+ });
+ return dashboard;
+}
diff --git a/public/app/features/dashboard-scene/scene/VariableControls.tsx b/public/app/features/dashboard-scene/scene/VariableControls.tsx
index a2e6f3daf88..4cd92d34614 100644
--- a/public/app/features/dashboard-scene/scene/VariableControls.tsx
+++ b/public/app/features/dashboard-scene/scene/VariableControls.tsx
@@ -39,8 +39,9 @@ export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
? restVariables.filter((v) => v.state.hide !== VariableHide.inControlsMenu)
: variables.filter(
(v) =>
+ // used for scopes variables, should always be hidden
// if we're editing in dynamic dashboards, still shows hidden variable but greyed out
- (isEditingNewLayouts && v.state.hide === VariableHide.hideVariable) ||
+ (!v.UNSAFE_renderAsHidden && isEditingNewLayouts && v.state.hide === VariableHide.hideVariable) ||
v.state.hide !== VariableHide.inControlsMenu
);