diff --git a/packages/calcite-components/src/components/link/link.e2e.ts b/packages/calcite-components/src/components/link/link.e2e.ts
index 32b8252b38a..fd46149220a 100644
--- a/packages/calcite-components/src/components/link/link.e2e.ts
+++ b/packages/calcite-components/src/components/link/link.e2e.ts
@@ -65,19 +65,19 @@ describe("calcite-link", () => {
expect(elementAsLink).not.toHaveAttribute("download");
});
- it("renders as a span with default props", async () => {
+ it("renders as a button with default props", async () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
const element = await page.find("calcite-link");
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(element).not.toHaveAttribute("icon-flip-rtl");
expect(elementAsLink).toBeNull();
- expect(elementAsSpan).not.toBeNull();
+ expect(elementAsButton).not.toBeNull();
expect(iconStart).toBeNull();
expect(iconEnd).toBeNull();
});
@@ -86,19 +86,19 @@ describe("calcite-link", () => {
const page = await newE2EPage({ html: `Continue` });
const link = await page.find("calcite-link");
let elementAsLink: E2EElement;
- let elementAsSpan: E2EElement;
+ let elementAsButton: E2EElement;
- elementAsSpan = await page.find("calcite-link >>> span");
+ elementAsButton = await page.find("calcite-link >>> button");
elementAsLink = await page.find("calcite-link >>> a");
- expect(elementAsSpan).not.toBeNull();
+ expect(elementAsButton).not.toBeNull();
expect(elementAsLink).toBeNull();
link.setProperty("href", "/");
await page.waitForChanges();
- elementAsSpan = await page.find("calcite-link >>> span");
+ elementAsButton = await page.find("calcite-link >>> button");
elementAsLink = await page.find("calcite-link >>> a");
- expect(elementAsSpan).toBeNull();
+ expect(elementAsButton).toBeNull();
expect(elementAsLink).not.toBeNull();
});
@@ -106,28 +106,28 @@ describe("calcite-link", () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
const element = await page.find("calcite-link");
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(element).not.toHaveAttribute("icon-flip-rtl");
expect(elementAsLink).not.toBeNull();
- expect(elementAsSpan).toBeNull();
+ expect(elementAsButton).toBeNull();
expect(iconStart).toBeNull();
expect(iconEnd).toBeNull();
});
- it("renders as a span with requested props", async () => {
+ it("renders as a button with requested props", async () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(elementAsLink).toBeNull();
- expect(elementAsSpan).not.toBeNull();
+ expect(elementAsButton).not.toBeNull();
expect(iconStart).toBeNull();
expect(iconEnd).toBeNull();
});
@@ -135,13 +135,13 @@ describe("calcite-link", () => {
it("renders as a link with requested props", async () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(elementAsLink).not.toBeNull();
- expect(elementAsSpan).toBeNull();
+ expect(elementAsButton).toBeNull();
expect(iconStart).toBeNull();
expect(iconEnd).toBeNull();
});
@@ -151,13 +151,13 @@ describe("calcite-link", () => {
await page.setContent(
`Continue`,
);
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(elementAsLink).not.toBeNull();
- expect(elementAsSpan).toBeNull();
+ expect(elementAsButton).toBeNull();
expect(elementAsLink).not.toHaveClass("my-custom-class");
expect(elementAsLink).toEqualAttribute("href", "google.com");
expect(elementAsLink).toEqualAttribute("rel", "noopener noreferrer");
@@ -169,12 +169,12 @@ describe("calcite-link", () => {
it("renders with an icon-start", async () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(elementAsLink).toBeNull();
- expect(elementAsSpan).not.toBeNull();
+ expect(elementAsButton).not.toBeNull();
expect(iconStart).not.toBeNull();
expect(iconEnd).toBeNull();
});
@@ -182,12 +182,12 @@ describe("calcite-link", () => {
it("renders with an icon-end", async () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(elementAsLink).toBeNull();
- expect(elementAsSpan).not.toBeNull();
+ expect(elementAsButton).not.toBeNull();
expect(iconStart).toBeNull();
expect(iconEnd).not.toBeNull();
});
@@ -195,12 +195,12 @@ describe("calcite-link", () => {
it("renders with an icon-start and icon-end", async () => {
const page = await newE2EPage();
await page.setContent(`Continue`);
- const elementAsSpan = await page.find("calcite-link >>> span");
+ const elementAsButton = await page.find("calcite-link >>> button");
const elementAsLink = await page.find("calcite-link >>> a");
const iconStart = await page.find("calcite-link >>> .calcite-link--icon.icon-start");
const iconEnd = await page.find("calcite-link >>> .calcite-link--icon.icon-end");
expect(elementAsLink).toBeNull();
- expect(elementAsSpan).not.toBeNull();
+ expect(elementAsButton).not.toBeNull();
expect(iconStart).not.toBeNull();
expect(iconEnd).not.toBeNull();
});
@@ -231,6 +231,18 @@ describe("calcite-link", () => {
expect(page.url()).toBe(targetUrl);
});
+ it("keyboard without href", async () => {
+ const element = await page.find("calcite-link");
+ element.setProperty("href", undefined);
+ const clickEvent = await element.spyOnEvent("click");
+
+ await element.callMethod("setFocus");
+ await page.waitForChanges();
+ await page.keyboard.press("Enter");
+ await page.waitForChanges();
+ expect(clickEvent).toHaveReceivedEventTimes(1);
+ });
+
it("mouse", async () => {
// workaround for https://github.com/puppeteer/puppeteer/issues/2977
await page.$eval("calcite-link", (link: HTMLElement): void => {
diff --git a/packages/calcite-components/src/components/link/link.scss b/packages/calcite-components/src/components/link/link.scss
index 1506886179f..16093a0efdd 100644
--- a/packages/calcite-components/src/components/link/link.scss
+++ b/packages/calcite-components/src/components/link/link.scss
@@ -12,7 +12,7 @@
// link base
:host a,
-:host span {
+:host button {
@apply font-inherit
relative
flex
@@ -34,7 +34,7 @@
// focus styles
:host a,
-:host span {
+:host button {
@apply focus-base;
&:focus {
@apply focus-outset;
@@ -63,7 +63,7 @@ calcite-icon {
}
:host {
- span,
+ button,
a {
@apply relative
inline
@@ -73,7 +73,8 @@ calcite-icon {
color: var(--calcite-link-text-color, var(--calcite-color-text-link));
line-height: inherit;
white-space: initial;
- background-image: linear-gradient(currentColor, currentColor),
+ background-image:
+ linear-gradient(currentColor, currentColor),
linear-gradient(var(--calcite-color-brand-underline), var(--calcite-color-brand-underline));
background-position-x: 0%, 100%;
background-position-y: min(1.5em, 100%);
diff --git a/packages/calcite-components/src/components/link/link.tsx b/packages/calcite-components/src/components/link/link.tsx
index 5089b373e91..4e55e66d4d5 100644
--- a/packages/calcite-components/src/components/link/link.tsx
+++ b/packages/calcite-components/src/components/link/link.tsx
@@ -22,7 +22,7 @@ declare global {
/**
* Any attributes placed on component will propagate to the rendered child
*
- * Passing a 'href' will render an anchor link, instead of a span. Role will be set to link, or link, depending on this.
+ * Passing a 'href' will render an anchor link, instead of a button.
*
* It is the consumers responsibility to add aria information, rel, target, for links, and any link attributes for form submission
*
@@ -38,7 +38,7 @@ export class Link extends LitElement implements InteractiveComponent {
// #region Private Properties
/** the rendered child element */
- private childEl: HTMLAnchorElement | HTMLSpanElement;
+ private childEl: HTMLAnchorElement | HTMLButtonElement;
// #endregion
@@ -131,7 +131,7 @@ export class Link extends LitElement implements InteractiveComponent {
override render(): JsxNode {
const { download, el } = this;
const dir = getElementDir(el);
- const childElType = this.href ? "a" : "span";
+ const childElType = this.href ? "a" : "button";
const iconStartEl = (
before. In Stencil, props overwrite user-provided props. If you don't wish to overwrite user-values, replace "=" here with "??=" */
this.el.role = "presentation";
@@ -178,7 +177,6 @@ export class Link extends LitElement implements InteractiveComponent {
onClick={this.childElClickHandler}
ref={this.storeTagRef}
rel={childElType === "a" && this.rel}
- role={role}
tabIndex={tabIndex}
target={childElType === "a" && this.target}
>