X/Twitter DOM Selector Reference

February 24, 2026 · View on GitHub

Last verified: February 2026. Twitter frequently changes their DOM — always verify selectors before use.

This is the canonical reference for all known X/Twitter DOM selectors used across the XActions project. Check here before writing new selectors.


Table of Contents


UserCell Elements

Search results, followers lists, following lists, and any user-list UI.

ElementPrimary SelectorFallback Selector(s)Notes
User cell container[data-testid="UserCell"][data-testid="user"], div[role="listitem"]Main container for user list items
Display name[data-testid="User-Name"][data-testid="UserCell"] a[href^="/"]Note the hyphen: User-Name
Display name link[data-testid="User-Name"] a—Direct link to profile
Handle link[data-testid="User-Name"] a[tabindex="-1"]—The @username portion
Bio/Description[data-testid="UserDescription"][dir="auto"]:not([data-testid]), [dir="auto"]:not([role])⚠️ Case-sensitive: capital U
Follow indicator[data-testid="userFollowIndicator"]—"Follows you" badge
Follow button[data-testid$="-follow"]button[aria-label*="Follow @"]Uses suffix match ($=)
Unfollow button[data-testid$="-unfollow"]button[aria-label*="Following @"]Uses suffix match ($=)
Verified badge[data-testid="icon-verified"]svg[aria-label*="Verified"]
Protected icon[data-testid="icon-lock"]svg[aria-label*="Protected"]
Avatar container[data-testid="UserAvatar-Container"]—
Avatar image[data-testid="UserAvatar-Container"] img[data-testid*="UserAvatar"] img
User actions menu[data-testid="userActions"]button[aria-label="More"]The "…" menu on user cells
Scrollable cell[data-testid="cellInnerDiv"]—Generic inner div for scrollable lists
Internal profile linka[href^="/"][role="link"]a[href^="/"]Username extraction from cells

Profile Page Elements

Selectors for profile pages (x.com/username).

ElementPrimary SelectorFallback Selector(s)Notes
Profile username[data-testid="UserName"]—⚠️ No hyphen (unlike User-Name in tweets)
Profile header items[data-testid="UserProfileHeader_Items"]—Container for location, URL, join date
Profile schema[data-testid="UserProfileSchema"]—Structured profile data
Bio/Description[data-testid="UserDescription"]—Same selector as UserCell
Location[data-testid="UserLocation"]—
Website URL[data-testid="UserUrl"]—
Website link[data-testid="UserUrl"] a—The clickable link element
Join date[data-testid="UserJoinDate"]—
Birthday[data-testid="UserBirthday"]—
Avatar (profile page)[data-testid="UserAvatar"] imga[href$="/photo"] img
Avatar (unknown variant)[data-testid="UserAvatar-Container-unknown"] img—Appears in some contexts
Header photoa[href$="/header_photo"] img—Banner image
Profile image (generic)img[src*="profile_images"]—Matches by URL pattern
Default avatarimg[src*="default_profile"]—Users with no profile pic
Followers linka[href$="/followers"]—
Followers counta[href$="/followers"] span—
Following linka[href$="/following"]—
Following counta[href$="/following"] span—
Verified followersa[href$="/verified_followers"]—
Premium badge[data-testid="premiumBadge"]—
Premium banner[data-testid="premiumBanner"]—
Premium linka[href*="premium"]—Premium upgrade link
Profile tab bar link[data-testid="AppTabBar_Profile_Link"]—Used for shadow-ban checking
Profile meta tagmeta[property="al:android:url"]—Profile detection via meta tag

Tweet Elements

Tweet/post containers, content, and metadata.

ElementPrimary SelectorFallback Selector(s)Notes
Tweet containerarticle[data-testid="tweet"]article[role="article"], [data-testid="cellInnerDiv"] articlePrimary tweet wrapper
Tweet text[data-testid="tweetText"][lang][dir] span, article span[dir="auto"]
Social context[data-testid="socialContext"]—"Retweeted", "Pinned", "Replying to"
Tweet photo[data-testid="tweetPhoto"]—Photo container
Tweet image[data-testid="tweetPhoto"] img—Actual image element
Video player[data-testid="videoPlayer"]—
Quote tweet[data-testid="quoteTweet"]—
Nested quote tweet[data-testid="tweet"] [data-testid="tweet"]—Quote inside a tweet
Card/link preview[data-testid="card.wrapper"]—
Thread indicator[data-testid="tweet-thread-indicator"]—
Promoted/Ad tweet[data-testid="placementTracking"]—Filter these to skip ads
Tweet permalinka[href*="/status/"]—Link to individual tweet
Tweet timestampa[href*="/status/"] time—
Timestamp elementtime—Generic time element
Tweet author avatar[data-testid="Tweet-User-Avatar"]—
Author name in tweet[data-testid="User-Name"] a[href^="/"]—Profile link from tweet

Engagement Buttons

Like, reply, retweet, bookmark, share, and analytics buttons on tweets.

ElementPrimary SelectorFallback Selector(s)Notes
Like button[data-testid="like"]button[aria-label*="Like"], [role="button"][data-testid*="like"]
Unlike button[data-testid="unlike"]button[aria-label*="Liked"]Already-liked state
Reply button[data-testid="reply"]button[aria-label*="Reply"]
Retweet/Repost button[data-testid="retweet"]button[aria-label*="Repost"]
Undo retweet[data-testid="unretweet"]button[aria-label*="Undo repost"]
Confirm retweet[data-testid="retweetConfirm"]—
Confirm undo retweet[data-testid="unretweetConfirm"]—
Bookmark button[data-testid="bookmark"]button[aria-label*="Bookmark"]
Remove bookmark[data-testid="removeBookmark"]button[aria-label*="Remove Bookmark"]
Share button[data-testid="share"]button[aria-label*="Share"]
More menu (caret)[data-testid="caret"]button[aria-label="More"], [data-testid="tweet"] button:last-of-typeThree-dot menu
Hide reply[data-testid="hideReply"]—
Reply restriction[data-testid="replyRestriction"]—
Analytics button[data-testid="analyticsButton"]—
Impressions count[data-testid="impressions"]—

Follow / Unfollow

ElementPrimary SelectorFallback Selector(s)Notes
Follow button[data-testid$="-follow"]button[aria-label*="Follow @"]Suffix match — username prefix varies
Unfollow button[data-testid$="-unfollow"]button[aria-label*="Following @"]Suffix match
Unblock button[data-testid$="-unblock"]button[aria-label*="Unblock"], button[aria-label*="Blocked"]Suffix match
Unmute button[data-testid$="-unmute"]button[aria-label*="Unmute"], button[aria-label*="Muted"]Suffix match
Placement button[data-testid="placementTracking"] [role="button"]—Follow/Unblock variant in placements

Compose / Post Creation

ElementPrimary SelectorFallback Selector(s)Notes
Compose tweet buttona[data-testid="SideNav_NewTweet_Button"][data-testid="SideNav_NewTweet_Button"]Sidebar compose button
Tweet textarea (first)[data-testid="tweetTextarea_0"][role="textbox"][data-testid], div[contenteditable="true"][role="textbox"]
Tweet textarea (any)[data-testid^="tweetTextarea_"]—Prefix match for threads
Tweet textarea (nth)[data-testid="tweetTextarea_${i}"]—Dynamic by index
Post/Tweet button[data-testid="tweetButton"]button[data-testid*="tweet"]
Inline tweet button[data-testid="tweetButtonInline"]—
Add thread "+"[data-testid="addButton"]—
Media file input[data-testid="fileInput"]input[data-testid="fileInput"]
Image file inputinput[data-testid="fileInput"][accept*="image"]—
Alt text input[data-testid="altTextInput"]—
Edit tweet[data-testid="editTweet"]—Premium feature
Delete tweet[data-testid="deleteTweet"]—
Quote tweet option[data-testid="quoteTweet"]—In retweet menu
Contenteditable textboxdiv[contenteditable="true"][role="textbox"]—Generic fallback

Compose Toolbar

ElementPrimary SelectorFallback Selector(s)Notes
Add poll[aria-label="Add poll"][data-testid="pollButton"]
Add GIF[aria-label="Add a GIF"][data-testid="gifyButton"]Note typo: gifyButton
Add emoji[aria-label="Add emoji"][data-testid="emojiButton"]
Location button[data-testid="geoButton"]—

Scheduling

ElementPrimary SelectorFallback Selector(s)Notes
Schedule option[data-testid="scheduleOption"][data-testid="scheduledButton"]
Date field[data-testid="scheduledDateField"][data-testid="scheduleDateInput"]Two known variants
Time field[data-testid="scheduledTimeField"][data-testid="scheduleTimeInput"]Two known variants
Schedule confirm[data-testid="scheduleConfirm"][data-testid="scheduledConfirmationPrimaryAction"]

Poll Elements

ElementPrimary SelectorNotes
Poll option inputs[data-testid="pollOption_0"] through [data-testid="pollOption_3"]0-indexed, max 4
Poll text inputs (variant)[data-testid="pollOptionTextInput_0"] through [data-testid="pollOptionTextInput_3"]Alternate testid
Add poll option[data-testid="addPollOption"][data-testid="addPollOptionButton"] variant
Poll duration[data-testid="pollDuration"]
Duration days[data-testid="pollDurationDays"]
Duration hours[data-testid="pollDurationHours"]
Duration minutes[data-testid="pollDurationMinutes"]
Remove poll[data-testid="removePoll"]
Poll results[data-testid="pollResults"]
Poll percentage[data-testid="pollPercentage"]
Poll total votes[data-testid="pollTotalVotes"]
Poll time remaining[data-testid="pollTimeRemaining"]
Radio option[role="radio"]Used in polls and settings
Poll group[role="group"]Container for poll options

Profile Editing

ElementPrimary SelectorNotes
Edit profile button[data-testid="editProfileButton"]
Save profile[data-testid="Profile_Save_Button"]
Edit avatar[data-testid="editProfileAvatar"]
Edit header[data-testid="editProfileHeader"]
Add avatar button[data-testid="addAvatarButton"]
Add banner button[data-testid="addBannerButton"]
Cancel button[data-testid="cancelButton"]
Sort by latest[data-testid="sortByLatest"]
Sort by liked[data-testid="sortByLiked"]
Name input fieldinput[name="displayName"]Used in edit profile modal
Bio textareatextarea[name="description"]Used in edit profile modal
Location inputinput[name="location"]Used in edit profile modal
Website URL inputinput[name="url"]Used in edit profile modal

ElementPrimary SelectorFallback Selector(s)Notes
Back button[data-testid="app-bar-back"]button[aria-label="Back"]
Primary column[data-testid="primaryColumn"]—Main content area
Sidebar column[data-testid="sidebarColumn"]—Right sidebar
Timeline sectionsection[role="region"]—
Tab list[role="tablist"]—
Individual tab[role="tab"]—
Active tab[role="tab"][aria-selected="true"]—
Main content[role="main"]—
Account switcher[data-testid="SideNav_AccountSwitcher_Button"]—
Sidebar avatardiv[data-testid="SideNav_AccountSwitcher_Button"] img—
Cell inner div[data-testid="cellInnerDiv"]—Generic scrollable cell
Profile tab link[data-testid="AppTabBar_Profile_Link"]—Profile link in app tab bar

Search / Explore

ElementPrimary SelectorFallback Selector(s)Notes
Search input[data-testid="SearchBox_Search_Input"]—
Typeahead result[data-testid="TypeaheadListItem"]—Autocomplete suggestions
Typeahead user[data-testid="TypeaheadUser"]—User in autocomplete
Trend item[data-testid="trend"][data-testid="trendItem"]Two known variants
Follow topic[data-testid="TopicFollow"]—

Direct Messages

ElementPrimary SelectorFallback Selector(s)Notes
New DM button[data-testid="NewDM_Button"]—
Search people[data-testid="searchPeople"]—DM people search
DM message input[data-testid="dmComposerTextInput"][role="textbox"][data-testid*="dm"]
DM send button[data-testid="dmComposerSendButton"]button[data-testid*="send"]
Conversation item[data-testid="conversation"]—In DM list
Message bubble[data-testid="messageEntry"]—Individual message
Last message preview[data-testid="lastMessage"]—
Unread indicator[data-testid="unread"]—
Message reaction[data-testid="messageReaction"]—
Message requests tab[data-testid="messageRequests"]—
Accept request[data-testid="acceptRequest"]—
Delete request[data-testid="deleteRequest"]—
Next button[data-testid="nextButton"]—"Next" in DM compose flow
DM scroller[data-testid="DmScrollerContainer"]—Scrollable message container
DM conversation[data-testid="DMConversation"]—
DM drawer/inbox[data-testid="DMDrawer"]—
DM conversation info[data-testid="DMConversationInfoButton"]—
DM image button[data-testid="DMImageButton"]—
DM GIF button[data-testid="DMGifButton"]—
GIF result[data-testid="gif"]—
Reaction emoji[data-testid="reactionEmoji"]—
DM conversation (variant)[data-testid="DM_Conversation"]—Underscore-separated variant
DM conversation avatar[data-testid="DM_Conversation_Avatar"]—Avatar in DM conversation list
Sent message indicator[data-testid="messageSent"]—Indicates message was sent

Block / Mute / Report

ElementPrimary SelectorFallback Selector(s)Notes
Block option[data-testid="block"][role="menuitem"] span:has-text("Block")In dropdown menu
Mute link[data-testid="muteLink"][role="menuitem"] span:has-text("Mute")
Mute option[data-testid="mute"]—Variant testid
Unmute option[data-testid="unmute"]—
Report option[data-testid="report"][role="menuitem"] span:has-text("Report")
Add muted word[data-testid="addMutedWord"]—
Muted word input[data-testid="mutedWordInput"]—
Save muted word[data-testid="saveMutedWord"]—
Report flow next[data-testid="ChoiceSelectionNextButton"]—Report wizard
Report reason options[role="radio"], [role="option"], button—Options in report/mute flows
Block inside menu[role="menuitem"] [data-testid="block"]—Block option nested in menu

Notifications

ElementPrimary SelectorNotes
Notification item[data-testid="notification"]
Notification text[data-testid="notification"] span
Settings toggle[data-testid="settingsSwitch"]

Bookmarks

ElementPrimary SelectorFallback Selector(s)Notes
Clear bookmarks[data-testid="clearBookmarks"][data-testid="clearAllBookmarks"]Two known variants
Bookmark folder[data-testid="bookmarkFolder"]—
Create folder[data-testid="createBookmarkFolder"]—
Confirm folder[data-testid="createFolderConfirm"]—
More options[aria-label="More"]—Shared with other contexts

Lists

ElementPrimary SelectorNotes
Create list[data-testid="createList"]
List name input[data-testid="listNameInput"]
List description input[data-testid="listDescriptionInput"]
Private toggle[data-testid="listPrivateToggle"]
Save list[data-testid="listSaveButton"]
Add members[data-testid="addMembers"]
List container[data-testid="list"]
List item[data-testid="listItem"]
List description[data-testid="listDescription"]
Member count[data-testid="memberCount"]
Done/save assignment[data-testid="addToListsButton"]
Checkbox (list select)[role="checkbox"]
List linksa[href*="/lists/"]
List headingh2[role="heading"]

Communities

ElementPrimary SelectorNotes
Joined/leave buttonbutton[aria-label^="Joined"]Prefix match
Join buttonbutton[aria-label^="Join"]Prefix match
Pending requestbutton[aria-label^="Pending"]Prefix match
Communities nava[aria-label="Communities"]Sidebar navigation link
Community linksa[href^="/i/communities/"]
Join community buttonbutton[data-testid="join"]
Community carddiv[data-testid="communityCard"][data-testid="CommunityCard"] variant
Community header[data-testid="communityHeader"]

Spaces / Live Audio

ElementPrimary SelectorNotes
Start Space button[data-testid="SpaceButton"]
Join Space[data-testid="joinSpace"]
Speaker list[data-testid="spaceSpeakers"]
Listener count[data-testid="spaceListeners"]
Recording indicator[data-testid="spaceRecording"]
Schedule Space[data-testid="scheduleSpace"]
Space topic[data-testid="spaceTopic"]
Space title[data-testid="spaceTitle"]
Space host[data-testid="spaceHost"]
Space card[data-testid="SpaceCard"][data-testid="space"] variant
Scheduled Space[data-testid="scheduledSpace"]
Individual speaker[data-testid="spaceSpeaker"]
Live indicator[data-testid="spaceLive"]
Space bar[data-testid="SpaceBar"]
Space linksa[href*="/i/spaces/"]
Space card media[data-testid="card.layoutLarge.media"]

Grok AI

ElementPrimary SelectorFallback Selector(s)Notes
Grok chat input[data-testid="grokInput"]textarea[placeholder*="Ask"], [contenteditable][role="textbox"]
Grok send button[data-testid="grokSendButton"]button[aria-label="Send"], button[data-testid*="send"]
Grok response area[data-testid="grokResponse"][data-testid="grokResponseText"]
Grok response text[data-testid="grokResponseText"]—
New chat button[data-testid="grokNewChat"]a[href="/i/grok"]
Grok image gen[data-testid="grokImageGen"]—
Chat history[data-testid="grokChatHistory"]—
Any Grok element[data-testid*="grok"]—Wildcard match

Articles / Longform

ElementPrimary SelectorFallback Selector(s)Notes
Article title input[data-testid="articleTitle"]h1[contenteditable], [contenteditable][aria-label*="title" i]
Article body editor[data-testid="articleBody"][data-testid="richTextEditor"], [contenteditable][role="textbox"]
Publish button[data-testid="articlePublish"]—
Save draft[data-testid="articleSaveDraft"]—
Cover image[data-testid="articleCoverImage"]—
Article list[data-testid="articleList"]—
Article card[data-testid="articleCard"]—
Article preview[data-testid="articlePreview"]—

Creator Studio / Monetization

ElementPrimary SelectorNotes
Engagements stat[data-testid="engagements"]
Followers chart[data-testid="followersChart"]
Revenue tab[data-testid="revenueTab"]
Subscription settings[data-testid="subscriptionSettings"]
Tips settings[data-testid="tipsSettings"]
Export analytics[data-testid="exportAnalytics"]
Analytics card[data-testid="analyticsCard"]
Stat elements[data-testid*="stat"]Wildcard match
Metric elements[data-testid*="metric"]Wildcard match
Subscription info[data-testid="subscriptionInfo"]
Analytics tab[data-testid="analyticsTab"]
Boost button[data-testid="boostButton"]
Ads dashboard[data-testid="adsDashboard"]
Campaign list[data-testid="campaignList"]
Create campaign[data-testid="createCampaign"]
List item (stats)[role="listitem"]
Analytics nav linka[href="/i/account_analytics"]
Monetization settingsa[href="/settings/monetization"]

Settings / Privacy

ElementPrimary SelectorNotes
Toggle switch[role="switch"]
Protected tweets[data-testid="protectedTweets"]
Settings save[data-testid="settingsSave"]
Request data[data-testid="requestData"]
Settings linksa[href^="/settings/"]
Option element[role="option"]
Account settingsa[href="/settings/account"]
Privacy & safetya[href="/settings/privacy_and_safety"]
Notifications settingsa[href="/settings/notifications"]
Download dataa[href="/settings/download_data"]
Deactivate accounta[href="/settings/deactivate"]
2FA settingsa[href="/settings/account/login_verification"]
Blocked accountsa[href="/settings/blocked"]
Muted accountsa[href="/settings/muted"]
Muted keywordsa[href="/settings/muted_keywords"]
Content preferencesa[href="/settings/content_preferences"]
Display settingsa[href="/settings/display"]

Dialogs / Confirmations

ElementPrimary SelectorFallback Selector(s)Notes
Confirm button[data-testid="confirmationSheetConfirm"][role="alertdialog"] button:nth-child(1)Unfollow, block, delete confirmations
Cancel button[data-testid="confirmationSheetCancel"][role="alertdialog"] button:last-child
Modal container[data-testid="modal"]—
Sheet dialog[data-testid="sheetDialog"]—
Toast notification[data-testid="toast"]—
Alert element[role="alert"]—
Dropdown menu[data-testid="Dropdown"]—
Menu item[role="menuitem"]—Items inside dropdown menus

Generic / Utility

Selectors used across many contexts as fallbacks or for text extraction.

ElementPrimary SelectorNotes
LTR text span[dir="ltr"] > spanDisplay names, counts
LTR span (variant)[dir="ltr"] spanLess specific
LTR element[dir="ltr"]Generic LTR container
Auto-dir (no testid)[dir="auto"]:not([data-testid])Bio/description fallback
Auto-dir (no role)[dir="auto"]:not([role])Bio/description fallback
Auto-dir generic[dir="auto"]Any auto-direction text
Internal linka[href^="/"]Any link within X
Internal link w/ rolea[href^="/"][role="link"]
Status permalinka[href*="/status/"]Tweet links
Analytics linka[href*="/analytics"]
Likes taba[href$="/likes"]
External linksa[href*="t.co"]Shortened URLs
Premium linka[href*="premium"]
Follow-related linksa[href*="/follow"]
Media imagesimg[src*="media"]
Video elementsvideo
SVG with testidsvg[data-testid]
Heading element[role="heading"]
Generic send buttonbutton[aria-label="Send"]
Any buttonbutton, [role="button"]Generic button matching
Link with rolea[role="link"]Accessible link element
Threads post container[data-pressable-container="true"]Meta Threads scraper only
Threads post fallbackdiv[role="article"]Meta Threads scraper only
Markdown response[class*="markdown"]Grok markdown-formatted text
Compose article linka[href="/compose/article"]Navigate to article composer
Grok nav linka[href="/i/grok"]Navigate to Grok AI
Spaces nav linka[href*="/spaces"]Navigate to Spaces
Bookmarks nav linka[href="/i/bookmarks"]Navigate to bookmarks

Common Pitfalls

Case Sensitivity

data-testid values are CASE-SENSITIVE:

  • ✅ UserDescription (capital U, capital D)
  • ❌ userdescription
  • ✅ User-Name (capital U, capital N, with hyphen)
  • ❌ user-name
  • ⚠️ UserName on profile pages vs User-Name in tweets — they are different selectors

Suffix Matchers for Follow/Unfollow

Follow/unfollow buttons include a username prefix in their data-testid:

data-testid="nichxbt-follow"
data-testid="nichxbt-unfollow"

Always use the suffix match ($=):

// ✅ Correct
document.querySelector('[data-testid$="-follow"]');

// ❌ Wrong — won't match
document.querySelector('[data-testid="follow"]');

Bio vs Display Name in UserCells

Multiple [dir="auto"] elements exist inside a UserCell. To find the bio:

// ✅ Best approach — use data-testid
cell.querySelector('[data-testid="UserDescription"]');

// ⚠️ Fallback — filter out elements inside links
const bioEl = [...cell.querySelectorAll('[dir="auto"]')]
  .filter(el => !el.closest('a') && !el.closest('[data-testid="User-Name"]'))
  .pop();

Browser console scripts stop when the page navigates. Use sessionStorage to persist state:

const getProcessed = () => {
  try { return JSON.parse(sessionStorage.getItem('xactions_key') || '[]'); }
  catch { return []; }
};

Confirmation Dialogs Are Required

Many destructive actions pop up a confirmation dialog. Always wait for and click it:

await sleep(500);
const confirm = document.querySelector('[data-testid="confirmationSheetConfirm"]');
if (confirm) confirm.click();

Filter out ads before processing tweets:

const isAd = tweet.closest('[data-testid="placementTracking"]');
if (isAd) continue;

Rate Limiting

Add delays between actions (1–3 seconds minimum). X will temporarily restrict your account if you bulk-act too fast.

DOM Changes

X/Twitter frequently updates their DOM. If a selector stops working:

  1. Check the browser DevTools for the current data-testid
  2. Look for aria-label alternatives
  3. Fall back to structural selectors (role, tag hierarchy)
  4. Update this document

Selector Architecture

The XActions codebase uses a fallback chain pattern for resilient selector matching.

Canonical Source Files

FilePurposeSelector Count
src/utils/core.jsPrimary fallback-chain registry~29 keys
src/automation/actions.jsAction-oriented selectors~40+ keys
src/automation/core.jsCore automation selectors~20+ keys
extension/content/injected.jsBrowser extension selectors~15 keys

Fallback Chain Pattern

// From src/utils/core.js — the canonical pattern
const SELECTORS = {
  tweet: [
    'article[data-testid="tweet"]',       // Primary: data-testid
    'article[role="article"]',             // Fallback 1: role
    '[data-testid="cellInnerDiv"] article' // Fallback 2: structural
  ],
  tweetText: [
    '[data-testid="tweetText"]',   // Primary
    '[lang][dir] span',            // Fallback 1
    'article span[dir="auto"]'     // Fallback 2
  ]
};

When writing new selectors:

  1. Primary: Use data-testid when available
  2. Fallback 1: Use aria-label or role attributes
  3. Fallback 2: Use structural/positional selectors as last resort
  4. Always add new selectors to this document

Contributing: When you discover a new selector or a changed one, update this file and the SELECTORS object in src/utils/core.js. Keep this document as the single source of truth.