Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/label-link-variant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@patternfly/elements": minor
---

`<pf-label>`: added the `href` attribute to render the label as a clickable link.
14 changes: 14 additions & 0 deletions elements/pf-label/demo/link.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<section>
<pf-label color="blue" href="#blue">Blue</pf-label>
<pf-label color="green" href="#green">Green</pf-label>
<pf-label color="orange" href="#orange">Orange</pf-label>
<pf-label color="red" href="#red"><span>Red <span class="visually-hidden-class">Hat</span></span></pf-label>
<pf-label color="purple" href="purple">Purple</pf-label>
<pf-label color="cyan" href="#cyan">Cyan</pf-label>
<pf-label color="gold" href="#gold">Gold</pf-label>
<pf-label href="#grey">Grey</pf-label>
</section>

<script type="module">
import '@patternfly/elements/pf-label/pf-label.js';
</script>
17 changes: 17 additions & 0 deletions elements/pf-label/pf-label.css
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,23 @@ pf-button {
margin-left: var(--pf-c-label__c-button--MarginLeft, 0.25rem);
}

#link {
color: inherit;
text-decoration: underline;
}

#link:hover {
text-decoration: none;
}

.link {
/** link label background color */
--pf-c-label--BackgroundColor: transparent;
/** link label border width */
--pf-c-label__content--before--BorderWidth: 0;
cursor: pointer;
}

svg {
vertical-align:-0.125em;
fill: currentColor;
Expand Down
12 changes: 11 additions & 1 deletion elements/pf-label/pf-label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { LitElement, html, isServer, type TemplateResult } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';
import { property } from 'lit/decorators/property.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';

import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js';

Expand Down Expand Up @@ -68,6 +69,9 @@ export class PfLabel extends LitElement {
/** Text label for a removable label's close button */
@property({ attribute: 'close-button-label' }) closeButtonLabel?: string;

/** When set, the label becomes a link. The label text renders inside an anchor element. */
@property({ reflect: true }) href?: string;

/** Represents the state of the anonymous and icon slots */
#slots = new SlotController(this, null, 'icon');

Expand All @@ -79,15 +83,17 @@ export class PfLabel extends LitElement {
}

override render(): TemplateResult<1> {
const { compact, truncated } = this;
const { compact, truncated, href } = this;
const { variant, color, icon } = this;
const hasIcon = !!icon || this.#slots.hasSlotted('icon');
const isLink = !!href;
return html`
<span id="container"
class="${classMap({
hasIcon,
compact,
truncated,
link: isLink,
[variant ?? '']: !!variant,
[color ?? '']: !!color })}">
<!-- slot:
Expand All @@ -101,7 +107,11 @@ export class PfLabel extends LitElement {
.icon="${this.icon || undefined as unknown as string}"></pf-icon>
</slot>
<!-- summary: Must contain the text for the label. -->
${isLink ? html`
<a id="link" href="${ifDefined(href)}"><slot id="text"></slot></a>
` : html`
<slot id="text"></slot>
`}
<!-- summary: container for removable labels' close button -->
<span part="close-button" ?hidden=${!this.removable}>
<pf-button plain
Expand Down
34 changes: 34 additions & 0 deletions elements/pf-label/test/pf-label.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const exampleWithCompactAttribute = html`
<pf-label compact>Default Compact</pf-label>
`;

const exampleWithHref = html`
<pf-label href="https://example.com">Link Label</pf-label>
`;


describe('<pf-label>', function() {
before(function() {
Expand Down Expand Up @@ -140,4 +144,34 @@ describe('<pf-label>', function() {
expect(containerStyles.getPropertyValue('padding-bottom')).to.equal('0px');
expect(containerStyles.getPropertyValue('padding-left')).to.equal('8px'); // 0.5rem = 8px @ 16px browser default
});

describe('with href attribute', function() {
let element: PfLabel;
beforeEach(async function() {
element = await createFixture<PfLabel>(exampleWithHref);
await element.updateComplete;
});

it('should render an anchor element', function() {
const link = element.shadowRoot!.querySelector('#link');
expect(link).to.be.an.instanceOf(HTMLAnchorElement);
});

it('should set the href on the anchor', function() {
const link = element.shadowRoot!.querySelector('#link') as HTMLAnchorElement;
expect(link.href).to.equal('https://example.com/');
});

it('should have a transparent background', function() {
const container = element.shadowRoot!.querySelector('#container')!;
expect(getComputedStyle(container).getPropertyValue('background-color')).to.equal('rgba(0, 0, 0, 0)');
});

it('should not render an anchor when href is not set', async function() {
const el = await createFixture<PfLabel>(example);
await el.updateComplete;
const link = el.shadowRoot!.querySelector('#link');
expect(link).to.be.null;
});
});
});
Loading