diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json
index b97808e5f..8b3f7093b 100644
--- a/arduino-ide-extension/package.json
+++ b/arduino-ide-extension/package.json
@@ -39,6 +39,7 @@
     "@theia/outline-view": "1.41.0",
     "@theia/output": "1.41.0",
     "@theia/plugin-ext": "1.41.0",
+    "@theia/plugin-ext-vscode": "1.41.0",
     "@theia/preferences": "1.41.0",
     "@theia/scm": "1.41.0",
     "@theia/search-in-workspace": "1.41.0",
diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
index 89b2b218d..2b170dd7b 100644
--- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
+++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
@@ -1,5 +1,9 @@
 import '../../src/browser/style/index.css';
-import { Container, ContainerModule } from '@theia/core/shared/inversify';
+import {
+  Container,
+  ContainerModule,
+  interfaces,
+} from '@theia/core/shared/inversify';
 import { WidgetFactory } from '@theia/core/lib/browser/widget-manager';
 import { CommandContribution } from '@theia/core/lib/common/command';
 import { bindViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
@@ -53,6 +57,8 @@ import {
   DockPanelRenderer as TheiaDockPanelRenderer,
   TabBarRendererFactory,
   ContextMenuRenderer,
+  createTreeContainer,
+  TreeWidget,
 } from '@theia/core/lib/browser';
 import { MenuContribution } from '@theia/core/lib/common/menu';
 import {
@@ -372,6 +378,15 @@ import { DebugSessionWidget } from '@theia/debug/lib/browser/view/debug-session-
 import { DebugConfigurationWidget } from './theia/debug/debug-configuration-widget';
 import { DebugConfigurationWidget as TheiaDebugConfigurationWidget } from '@theia/debug/lib/browser/view/debug-configuration-widget';
 import { DebugToolBar } from '@theia/debug/lib/browser/view/debug-toolbar-widget';
+import {
+  PluginTree,
+  PluginTreeModel,
+  TreeViewWidgetOptions,
+  VIEW_ITEM_CONTEXT_MENU,
+} from '@theia/plugin-ext/lib/main/browser/view/tree-view-widget';
+import { TreeViewDecoratorService } from '@theia/plugin-ext/lib/main/browser/view/tree-view-decorator-service';
+import { PLUGIN_VIEW_DATA_FACTORY_ID } from '@theia/plugin-ext/lib/main/browser/view/plugin-view-registry';
+import { TreeViewWidget } from './theia/plugin-ext/tree-view-widget';
 
 // Hack to fix copy/cut/paste issue after electron version update in Theia.
 // https://github.com/eclipse-theia/theia/issues/12487
@@ -1082,4 +1097,43 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
   rebind(TheiaTerminalFrontendContribution).toService(
     TerminalFrontendContribution
   );
+
+  bindViewsWelcome_TheiaGH14309({ bind, widget: TreeViewWidget });
 });
+
+// Align the viewsWelcome rendering with VS Code (https://github.com/eclipse-theia/theia/issues/14309)
+// Copied from Theia code but with customized TreeViewWidget with the customized viewsWelcome rendering
+// https://github.com/eclipse-theia/theia/blob/0c5f69455d9ee355b1a7ca510ffa63d2b20f0c77/packages/plugin-ext/src/main/browser/plugin-ext-frontend-module.ts#L159-L181
+function bindViewsWelcome_TheiaGH14309({
+  bind,
+  widget,
+}: {
+  bind: interfaces.Bind;
+  widget: interfaces.Newable<TreeWidget>;
+}) {
+  bind(WidgetFactory)
+    .toDynamicValue(({ container }) => ({
+      id: PLUGIN_VIEW_DATA_FACTORY_ID,
+      createWidget: (options: TreeViewWidgetOptions) => {
+        const props = {
+          contextMenuPath: VIEW_ITEM_CONTEXT_MENU,
+          expandOnlyOnExpansionToggleClick: true,
+          expansionTogglePadding: 22,
+          globalSelection: true,
+          leftPadding: 8,
+          search: true,
+          multiSelect: options.multiSelect,
+        };
+        const child = createTreeContainer(container, {
+          props,
+          tree: PluginTree,
+          model: PluginTreeModel,
+          widget,
+          decoratorService: TreeViewDecoratorService,
+        });
+        child.bind(TreeViewWidgetOptions).toConstantValue(options);
+        return child.get(TreeWidget);
+      },
+    }))
+    .inSingletonScope();
+}
diff --git a/arduino-ide-extension/src/browser/theia/plugin-ext/tree-view-widget.tsx b/arduino-ide-extension/src/browser/theia/plugin-ext/tree-view-widget.tsx
new file mode 100644
index 000000000..dc83272c2
--- /dev/null
+++ b/arduino-ide-extension/src/browser/theia/plugin-ext/tree-view-widget.tsx
@@ -0,0 +1,241 @@
+import { LabelIcon } from '@theia/core/lib/browser/label-parser';
+import { OpenerService, open } from '@theia/core/lib/browser/opener-service';
+import { codicon } from '@theia/core/lib/browser/widgets/widget';
+import { DisposableCollection } from '@theia/core/lib/common/disposable';
+import { URI } from '@theia/core/lib/common/uri';
+import { inject, injectable } from '@theia/core/shared/inversify';
+import React from '@theia/core/shared/react';
+import { URI as CodeUri } from '@theia/core/shared/vscode-uri';
+import { TreeViewWidget as TheiaTreeViewWidget } from '@theia/plugin-ext/lib/main/browser/view/tree-view-widget';
+
+// Copied back from https://github.com/eclipse-theia/theia/pull/14391
+// Remove the patching when Arduino uses Eclipse Theia >1.55.0
+// https://github.com/eclipse-theia/theia/blob/8d3c5a11af65448b6700bedd096f8d68f0675541/packages/core/src/browser/tree/tree-view-welcome-widget.tsx#L37-L54
+// https://github.com/eclipse-theia/theia/blob/8d3c5a11af65448b6700bedd096f8d68f0675541/packages/core/src/browser/tree/tree-view-welcome-widget.tsx#L146-L298
+
+interface ViewWelcome {
+  readonly view: string;
+  readonly content: string;
+  readonly when?: string;
+  readonly enablement?: string;
+  readonly order: number;
+}
+
+export interface IItem {
+  readonly welcomeInfo: ViewWelcome;
+  visible: boolean;
+}
+
+export interface ILink {
+  readonly label: string;
+  readonly href: string;
+  readonly title?: string;
+}
+
+type LinkedTextItem = string | ILink;
+
+@injectable()
+export class TreeViewWidget extends TheiaTreeViewWidget {
+  @inject(OpenerService)
+  private readonly openerService: OpenerService;
+
+  private readonly toDisposeBeforeUpdateViewWelcomeNodes =
+    new DisposableCollection();
+
+  protected override updateViewWelcomeNodes(): void {
+    this.viewWelcomeNodes = [];
+    this.toDisposeBeforeUpdateViewWelcomeNodes.dispose();
+    const items = this.visibleItems.sort((a, b) => a.order - b.order);
+
+    const enablementKeys: Set<string>[] = [];
+    // the plugin-view-registry will push the changes when there is a change in the `when` prop  which controls the visibility
+    // this listener is to update the enablement of the components in the view welcome
+    this.toDisposeBeforeUpdateViewWelcomeNodes.push(
+      this.contextService.onDidChange((event) => {
+        if (enablementKeys.some((keys) => event.affects(keys))) {
+          this.updateViewWelcomeNodes();
+          this.update();
+        }
+      })
+    );
+    // Note: VS Code does not support the `renderSecondaryButtons` prop in welcome content either.
+    for (const item of items) {
+      const { content } = item;
+      const enablement = isEnablementAware(item) ? item.enablement : undefined;
+      const itemEnablementKeys = enablement
+        ? this.contextService.parseKeys(enablement)
+        : undefined;
+      if (itemEnablementKeys) {
+        enablementKeys.push(itemEnablementKeys);
+      }
+      const lines = content.split('\n');
+
+      for (let line of lines) {
+        line = line.trim();
+
+        if (!line) {
+          continue;
+        }
+
+        const linkedTextItems = this.parseLinkedText_patch14309(line);
+
+        if (
+          linkedTextItems.length === 1 &&
+          typeof linkedTextItems[0] !== 'string'
+        ) {
+          const node = linkedTextItems[0];
+          this.viewWelcomeNodes.push(
+            this.renderButtonNode_patch14309(
+              node,
+              this.viewWelcomeNodes.length,
+              enablement
+            )
+          );
+        } else {
+          const renderNode = (item: LinkedTextItem, index: number) =>
+            typeof item == 'string'
+              ? this.renderTextNode_patch14309(item, index)
+              : this.renderLinkNode_patch14309(item, index, enablement);
+
+          this.viewWelcomeNodes.push(
+            <p key={`p-${this.viewWelcomeNodes.length}`}>
+              {...linkedTextItems.flatMap(renderNode)}
+            </p>
+          );
+        }
+      }
+    }
+  }
+
+  private renderButtonNode_patch14309(
+    node: ILink,
+    lineKey: string | number,
+    enablement: string | undefined
+  ): React.ReactNode {
+    return (
+      <div key={`line-${lineKey}`} className="theia-WelcomeViewButtonWrapper">
+        <button
+          title={node.title}
+          className="theia-button theia-WelcomeViewButton"
+          disabled={!this.isEnabledClick_patch14309(enablement)}
+          onClick={(e) => this.openLinkOrCommand_patch14309(e, node.href)}
+        >
+          {node.label}
+        </button>
+      </div>
+    );
+  }
+
+  private renderTextNode_patch14309(
+    node: string,
+    textKey: string | number
+  ): React.ReactNode {
+    return (
+      <span key={`text-${textKey}`}>
+        {this.labelParser
+          .parse(node)
+          .map((segment, index) =>
+            LabelIcon.is(segment) ? (
+              <span key={index} className={codicon(segment.name)} />
+            ) : (
+              <span key={index}>{segment}</span>
+            )
+          )}
+      </span>
+    );
+  }
+
+  private renderLinkNode_patch14309(
+    node: ILink,
+    linkKey: string | number,
+    enablement: string | undefined
+  ): React.ReactNode {
+    return (
+      <a
+        key={`link-${linkKey}`}
+        className={this.getLinkClassName_patch14309(node.href, enablement)}
+        title={node.title || ''}
+        onClick={(e) => this.openLinkOrCommand_patch14309(e, node.href)}
+      >
+        {node.label}
+      </a>
+    );
+  }
+
+  private getLinkClassName_patch14309(
+    href: string,
+    enablement: string | undefined
+  ): string {
+    const classNames = ['theia-WelcomeViewCommandLink'];
+    // Only command-backed links can be disabled. All other, https:, file: remain enabled
+    if (
+      href.startsWith('command:') &&
+      !this.isEnabledClick_patch14309(enablement)
+    ) {
+      classNames.push('disabled');
+    }
+    return classNames.join(' ');
+  }
+
+  private isEnabledClick_patch14309(enablement: string | undefined): boolean {
+    return typeof enablement === 'string'
+      ? this.contextService.match(enablement)
+      : true;
+  }
+
+  private openLinkOrCommand_patch14309 = (
+    event: React.MouseEvent,
+    value: string
+  ): void => {
+    event.stopPropagation();
+
+    if (value.startsWith('command:')) {
+      const command = value.replace('command:', '');
+      this.commands.executeCommand(command);
+    } else if (value.startsWith('file:')) {
+      const uri = value.replace('file:', '');
+      open(this.openerService, new URI(CodeUri.file(uri).toString()));
+    } else {
+      this.windowService.openNewWindow(value, { external: true });
+    }
+  };
+
+  private parseLinkedText_patch14309(text: string): LinkedTextItem[] {
+    const result: LinkedTextItem[] = [];
+
+    const linkRegex =
+      /\[([^\]]+)\]\(((?:https?:\/\/|command:|file:)[^\)\s]+)(?: (["'])(.+?)(\3))?\)/gi;
+    let index = 0;
+    let match: RegExpExecArray | null;
+
+    while ((match = linkRegex.exec(text))) {
+      if (match.index - index > 0) {
+        result.push(text.substring(index, match.index));
+      }
+
+      const [, label, href, , title] = match;
+
+      if (title) {
+        result.push({ label, href, title });
+      } else {
+        result.push({ label, href });
+      }
+
+      index = match.index + match[0].length;
+    }
+
+    if (index < text.length) {
+      result.push(text.substring(index));
+    }
+
+    return result;
+  }
+}
+
+interface EnablementAware {
+  readonly enablement: string | undefined;
+}
+
+function isEnablementAware(arg: unknown): arg is EnablementAware {
+  return !!arg && typeof arg === 'object' && 'enablement' in arg;
+}
diff --git a/arduino-ide-extension/src/node/arduino-ide-backend-module.ts b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts
index 02d534044..4eb572b3b 100644
--- a/arduino-ide-extension/src/node/arduino-ide-backend-module.ts
+++ b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts
@@ -116,12 +116,16 @@ import { MessagingContribution } from './theia/core/messaging-contribution';
 import { MessagingService } from '@theia/core/lib/node/messaging/messaging-service';
 import { HostedPluginReader } from './theia/plugin-ext/plugin-reader';
 import { HostedPluginReader as TheiaHostedPluginReader } from '@theia/plugin-ext/lib/hosted/node/plugin-reader';
-import { PluginDeployer } from '@theia/plugin-ext/lib/common/plugin-protocol';
+import {
+  PluginDeployer,
+  PluginScanner,
+} from '@theia/plugin-ext/lib/common/plugin-protocol';
 import {
   LocalDirectoryPluginDeployerResolverWithFallback,
   PluginDeployer_GH_12064,
 } from './theia/plugin-ext/plugin-deployer';
 import { SettingsReader } from './settings-reader';
+import { VsCodePluginScanner } from './theia/plugin-ext-vscode/scanner-vscode';
 
 export default new ContainerModule((bind, unbind, isBound, rebind) => {
   bind(BackendApplication).toSelf().inSingletonScope();
@@ -410,6 +414,11 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
   rebind(PluginDeployer).to(PluginDeployer_GH_12064).inSingletonScope();
 
   bind(SettingsReader).toSelf().inSingletonScope();
+
+  // To read the enablement property of the viewsWelcome
+  // https://github.com/eclipse-theia/theia/issues/14309
+  bind(VsCodePluginScanner).toSelf().inSingletonScope();
+  rebind(PluginScanner).toService(VsCodePluginScanner);
 });
 
 function bindChildLogger(bind: interfaces.Bind, name: string): void {
diff --git a/arduino-ide-extension/src/node/theia/plugin-ext-vscode/scanner-vscode.ts b/arduino-ide-extension/src/node/theia/plugin-ext-vscode/scanner-vscode.ts
new file mode 100644
index 000000000..0fd68c9b4
--- /dev/null
+++ b/arduino-ide-extension/src/node/theia/plugin-ext-vscode/scanner-vscode.ts
@@ -0,0 +1,44 @@
+import { injectable, postConstruct } from '@theia/core/shared/inversify';
+import { VsCodePluginScanner as TheiaVsCodePluginScanner } from '@theia/plugin-ext-vscode/lib/node/scanner-vscode';
+import {
+  PluginPackageViewWelcome,
+  ViewWelcome,
+} from '@theia/plugin-ext/lib/common/plugin-protocol';
+
+@injectable()
+export class VsCodePluginScanner extends TheiaVsCodePluginScanner {
+  @postConstruct()
+  protected init(): void {
+    this['readViewWelcome'] = (
+      rawViewWelcome: PluginPackageViewWelcome,
+      pluginViewsIds: string[]
+    ) => {
+      const result = {
+        view: rawViewWelcome.view,
+        content: rawViewWelcome.contents,
+        when: rawViewWelcome.when,
+        // if the plugin contributes Welcome view to its own view - it will be ordered first
+        order:
+          pluginViewsIds.findIndex((v) => v === rawViewWelcome.view) > -1
+            ? 0
+            : 1,
+      };
+      return maybeSetEnablement(rawViewWelcome, result);
+    };
+  }
+}
+
+// This is not yet supported by Theia but available in Code (https://github.com/microsoft/vscode/issues/114304)
+function maybeSetEnablement(
+  rawViewWelcome: PluginPackageViewWelcome,
+  result: ViewWelcome
+) {
+  const enablement =
+    'enablement' in rawViewWelcome &&
+    typeof rawViewWelcome['enablement'] === 'string' &&
+    rawViewWelcome['enablement'];
+  if (enablement) {
+    Object.assign(result, { enablement });
+  }
+  return result;
+}