diff --git a/src/locales/en.json b/src/locales/en.json
index a683bbc18ee..919aac4db59 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -364,7 +364,8 @@
"pad.gritter.unacceptedCommit.text": "Your recent edit is still not saved. Reconnect and try again.",
"pad.share": "Share this pad",
- "pad.share.readonly": "Read only",
+ "pad.share.readonly": "Use read-only link",
+ "pad.share.readonly-explanation": "This only changes the link and embed code shown here. Keep the editable link to make changes; people with permission to edit can still use that link.",
"pad.share.link": "Link",
"pad.share.emebdcode": "Embed URL",
"pad.chat": "Chat",
diff --git a/src/templates/pad.html b/src/templates/pad.html
index 1a1efe19b3d..63c1c51f76e 100644
--- a/src/templates/pad.html
+++ b/src/templates/pad.html
@@ -579,8 +579,9 @@
<% e.begin_block("embedPopup"); %>
diff --git a/src/tests/frontend-new/specs/share_readonly.spec.ts b/src/tests/frontend-new/specs/share_readonly.spec.ts
new file mode 100644
index 00000000000..07beee12239
--- /dev/null
+++ b/src/tests/frontend-new/specs/share_readonly.spec.ts
@@ -0,0 +1,55 @@
+import {expect, test} from '@playwright/test';
+import {getPadBody, goToNewPad} from '../helper/padHelper';
+
+test.use({locale: 'en-US'});
+
+test.beforeEach(async ({page}) => {
+ await goToNewPad(page);
+ await page.locator('.buttonicon-embed').click();
+ await expect(page.locator('#embed.popup-show')).toBeVisible();
+});
+
+test('explains that read-only sharing selects a link, not pad permissions', async ({page}) => {
+ const checkbox = page.getByRole('checkbox', {name: 'Use read-only link', exact: true});
+ const explanation = 'This only changes the link and embed code shown here. ' +
+ 'Keep the editable link to make changes; people with permission to edit can still use that link.';
+ await expect(checkbox).toBeAttached();
+ await expect(page.locator('#readonly-explanation')).toHaveText(explanation);
+ await expect(page.locator('#readonly-explanation')).toBeVisible();
+ await expect(checkbox).toHaveAccessibleDescription(explanation);
+ await expect(page.locator('label[for="readonlyinput"]')).toBeVisible();
+});
+
+test('switches share links without changing access through either link', async ({page, context}) => {
+ const editableUrl = page.url();
+ const checkbox = page.locator('#readonlyinput');
+ const label = page.locator('label[for="readonlyinput"]');
+ await expect(page.locator('#linkinput')).toHaveValue(editableUrl);
+ await label.click();
+ await expect(checkbox).toBeChecked();
+ await expect(page.locator('#linkinput')).toHaveValue(/\/p\/r\./);
+ const readonlyUrl = await page.locator('#linkinput').inputValue();
+ expect(await page.locator('#embedinput').inputValue()).toContain(`src="${readonlyUrl}?`);
+ await expect(page.locator('#embedinput')).toHaveValue(/name="embed_readonly"/);
+ await expect(page).toHaveURL(editableUrl);
+ await expect(await getPadBody(page)).toHaveAttribute('contenteditable', 'true');
+
+ await label.click();
+ await expect(checkbox).not.toBeChecked();
+ await expect(page.locator('#linkinput')).toHaveValue(editableUrl);
+ await expect(page.locator('#embedinput')).toHaveValue(/name="embed_readwrite"/);
+
+ const reader = await context.newPage();
+ await reader.goto(readonlyUrl);
+ await reader.waitForSelector('#editorcontainer.initialized');
+ await expect(await getPadBody(reader)).toHaveAttribute('contenteditable', 'false');
+ await reader.locator('.buttonicon-embed').click();
+ await expect(reader.locator('#embed.popup-show')).toBeVisible();
+ await expect(reader.locator('#embedreadonly')).toBeHidden();
+ await expect(reader.locator('#linkinput')).toHaveValue(readonlyUrl);
+
+ await page.reload();
+ await page.waitForSelector('#editorcontainer.initialized');
+ await expect(await getPadBody(page)).toHaveAttribute('contenteditable', 'true');
+ await reader.close();
+});