Change:
!
<!-- -96bd-47a8-a0e8- --This feature request is now a candidate for our backlog. The community has 60 days to the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our . Happy Coding!
<!-- -c9e0-7adb-d31b- --:slightlysmilingface: This feature request received a sufficient number of community upvotes and we moved it to our backlog. To learn more about how we handle feature requests, please see our . Happy Coding!
We closed this issue because we in the foreseeable future. If you disagree and feel that this issue is crucial: we are happy to listen and to reconsider. If you wonder what we are up to, please see our and . Thanks for your understanding, and happy coding!
Why has this been marked out of scope? This is a feature that was .
facing the same
Same problem here. This IS crucial for big projects.
To verify: renames should rename matching tags now. Test on both html tag names () and custom components () you change , then renaming custom components should instead renaming all references to that component

Discussion:
"description": "%typescript.preferences.useAliasesForRenames%", "scope": "language-overridable" }, <ins> "javascript.preferences.renameMatchingJsxTags": { "type": "boolean", "default": true, "description": "%typescript.preferences.renameMatchingJsxTags%", "scope": "language-overridable" }, "typescript.preferences.renameMatchingJsxTags": { "type": "boolean", "default": true, "description": "%typescript.preferences.renameMatchingJsxTags%", "scope": "language-overridable" }, </ins> "typescript.updateImportsOnFileMove.enabled": { "type": "string", "enum": [

"configuration.tsserver.watchOptions.synchronousWatchDirectory": "Disable deferred watching on directories. Deferred watching is useful when lots of file changes might occur at once (e.g. a change in node_modules from running npm install), but you might want to disable it with this flag for some less-common setups.", "typescript.preferences.renameShorthandProperties.deprecationMessage": "The setting 'typescript.preferences.renameShorthandProperties' has been deprecated in favor of 'typescript.preferences.useAliasesForRenames'", "typescript.preferences.useAliasesForRenames": "Enable/disable introducing aliases for object shorthand properties during renames.", <ins> "typescript.preferences.renameMatchingJsxTags": "When on a JSX tag, try to rename the matching tag instead of renaming the symbol. Requires using TypeScript 5.1+ in the workspace.", </ins> "typescript.workspaceSymbols.scope": "Controls which files are searched by [Go to Symbol in Workspace](https://code.visualstudio.com/docs/editor/editingevolved#_open-symbol-by-name).", "typescript.workspaceSymbols.scope.allOpenProjects": "Search all open JavaScript or TypeScript projects for symbols.", "typescript.workspaceSymbols.scope.currentProject": "Only search for symbols in the current JavaScript or TypeScript project.",

import * as path from 'path'; import * as vscode from 'vscode'; import { DocumentSelector } from '../configuration/documentSelector'; <ins> import * as languageIds from '../configuration/languageIds'; </ins> import { API } from '../tsServer/api'; import type * as Proto from '../tsServer/protocol/protocol'; import * as typeConverters from '../typeConverters'; <del> import { ClientCapability, ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; </del> <ins> import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; </ins> import FileConfigurationManager from './fileConfigurationManager'; import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration'; <ins> import { LanguageDescription } from '../configuration/languageDescription'; type RenameResponse = { readonly type: 'rename'; readonly body: Proto.RenameResponseBody; } | { readonly type: 'jsxLinkedEditing'; readonly spans: readonly Proto.TextSpan[]; }; </ins> class TypeScriptRenameProvider implements vscode.RenameProvider { public constructor( <ins> private readonly language: LanguageDescription, </ins> private readonly client: ITypeScriptServiceClient, private readonly fileConfigurationManager: FileConfigurationManager ) { }

document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken <del> ): Promise<vscode.Range | null> { </del> <ins> ): Promise<vscode.Range | undefined> { </ins> if (this.client.apiVersion.lt(API.v310)) { <del> return null; </del> <ins> return undefined; </ins> } const response = await this.execRename(document, position, token); <del> if (response?.type !== 'response' || !response.body) { return null; </del> <ins> if (!response) { return undefined; </ins> } <del> const renameInfo = response.body.info; if (!renameInfo.canRename) { return Promise.reject<vscode.Range>(renameInfo.localizedErrorMessage); </del> <ins> switch (response.type) { case 'rename': { const renameInfo = response.body.info; if (!renameInfo.canRename) { return Promise.reject<vscode.Range>(renameInfo.localizedErrorMessage); } return typeConverters.Range.fromTextSpan(renameInfo.triggerSpan); } case 'jsxLinkedEditing': { return response.spans .map(typeConverters.Range.fromTextSpan) .find(range => range.contains(position)); } </ins> } <del> return typeConverters.Range.fromTextSpan(renameInfo.triggerSpan); </del> } public async provideRenameEdits(

position: vscode.Position, newName: string, token: vscode.CancellationToken <del> ): Promise<vscode.WorkspaceEdit | null> { const response = await this.execRename(document, position, token); if (!response || response.type !== 'response' || !response.body) { return null; </del> <ins> ): Promise<vscode.WorkspaceEdit | undefined> { const file = this.client.toOpenTsFilePath(document); if (!file) { return undefined; </ins> } <del> const renameInfo = response.body.info; if (!renameInfo.canRename) { return Promise.reject<vscode.WorkspaceEdit>(renameInfo.localizedErrorMessage); </del> <ins> const response = await this.execRename(document, position, token); if (!response || token.isCancellationRequested) { return undefined; </ins> } <del> if (renameInfo.fileToRename) { const edits = await this.renameFile(renameInfo.fileToRename, newName, token); if (edits) { return edits; } else { return Promise.reject<vscode.WorkspaceEdit>(vscode.l10n.t("An error occurred while renaming file")); </del> <ins> switch (response.type) { case 'rename': { const renameInfo = response.body.info; if (!renameInfo.canRename) { return Promise.reject<vscode.WorkspaceEdit>(renameInfo.localizedErrorMessage); } if (renameInfo.fileToRename) { const edits = await this.renameFile(renameInfo.fileToRename, newName, token); if (edits) { return edits; } else { return Promise.reject<vscode.WorkspaceEdit>(vscode.l10n.t("An error occurred while renaming file")); } } return this.updateLocs(response.body.locs, newName); } case 'jsxLinkedEditing': { return this.updateLocs([{ file, locs: response.spans.map((span): Proto.RenameTextSpan => ({ ...span })), }], newName); </ins> } } <del> return this.updateLocs(response.body.locs, newName); </del> } public async execRename( document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken <del> ): Promise<ServerResponse.Response<Proto.RenameResponse> | undefined> { </del> <ins> ): Promise<RenameResponse | undefined> { </ins> const file = this.client.toOpenTsFilePath(document); if (!file) { return undefined; } <ins> // Prefer renaming matching jsx tag when available if (this.client.apiVersion.gte(API.v510) && vscode.workspace.getConfiguration(this.language.id).get('preferences.renameMatchingJsxTags', true) && this.looksLikePotentialJsxTagContext(document, position) ) { const args = typeConverters.Position.toFileLocationRequestArgs(file, position); const response = await this.client.execute('linkedEditingRange', args, token); if (response.type !== 'response' || !response.body) { return undefined; } return { type: 'jsxLinkedEditing', spans: response.body.ranges }; } </ins> const args: Proto.RenameRequestArgs = { ...typeConverters.Position.toFileLocationRequestArgs(file, position), findInStrings: false, findInComments: false }; <del> return this.client.interruptGetErr(() => { </del> <ins> return this.client.interruptGetErr(async () => { </ins> this.fileConfigurationManager.ensureConfigurationForDocument(document, token); <del> return this.client.execute('rename', args, token); </del> <ins> const response = await this.client.execute('rename', args, token); if (response.type !== 'response' || !response.body) { return undefined; } return { type: 'rename', body: response.body }; </ins> }); } <ins> private looksLikePotentialJsxTagContext(document: vscode.TextDocument, position: vscode.Position): boolean { if (![languageIds.typescriptreact, languageIds.javascript, languageIds.javascriptreact].includes(document.languageId)) { return false; } const prefix = document.getText(new vscode.Range(position.line, 0, position.line, position.character)); return /</?s*[wd_$.]*$/.test(prefix); } </ins> private updateLocs( locations: ReadonlyArray<Proto.SpanGroup>, newName: string

export function register( selector: DocumentSelector, <ins> language: LanguageDescription, </ins> client: ITypeScriptServiceClient, fileConfigurationManager: FileConfigurationManager, ) {

requireSomeCapability(client, ClientCapability.Semantic), ], () => { return vscode.languages.registerRenameProvider(selector.semantic, <del> new TypeScriptRenameProvider(client, fileConfigurationManager)); </del> <ins> new TypeScriptRenameProvider(language, client, fileConfigurationManager)); </ins> }); }

import('./languageFeatures/quickFix').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.client.diagnosticsManager, this.telemetryReporter))), import('./languageFeatures/refactor').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.telemetryReporter))), import('./languageFeatures/references').then(provider => this._register(provider.register(selector, this.client))), <del> import('./languageFeatures/rename').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager))), </del> <ins> import('./languageFeatures/rename').then(provider => this._register(provider.register(selector, this.description, this.client, this.fileConfigurationManager))), </ins> import('./languageFeatures/semanticTokens').then(provider => this._register(provider.register(selector, this.client))), import('./languageFeatures/signatureHelp').then(provider => this._register(provider.register(selector, this.client))), import('./languageFeatures/smartSelect').then(provider => this._register(provider.register(selector, this.client))),