diff --git a/.changeset/wise-stingrays-heal.md b/.changeset/wise-stingrays-heal.md
new file mode 100644
index 00000000000..f5504eba9ac
--- /dev/null
+++ b/.changeset/wise-stingrays-heal.md
@@ -0,0 +1,5 @@
+---
+"@hashicorp/design-system-components": minor
+---
+
+`Card` - Add `tag` argument to choose between using a `div` tag (the default) or an `li` tag
diff --git a/packages/components/src/components/hds/card/container.hbs b/packages/components/src/components/hds/card/container.hbs
index 404c9f8e100..6666c26716d 100644
--- a/packages/components/src/components/hds/card/container.hbs
+++ b/packages/components/src/components/hds/card/container.hbs
@@ -2,6 +2,14 @@
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
}}
-
- {{yield}}
-
\ No newline at end of file
+{{!
+ Dynamically generating an HTML tag in Ember creates a dynamic component class (with the corresponding tagName), while rendering
+ a plain HTML element requires less computing cycles for Ember (you will notice it doesn't add the `ember-view` class to it).
+}}
+{{#if (eq this.componentTag "div")}}
+ {{yield}}
+{{else}}
+ {{#let (element this.componentTag) as |Tag|}}
+ {{yield}}
+ {{/let}}
+{{/if}}
\ No newline at end of file
diff --git a/packages/components/src/components/hds/card/container.ts b/packages/components/src/components/hds/card/container.ts
index cb230e72ceb..3c21b9dd5df 100644
--- a/packages/components/src/components/hds/card/container.ts
+++ b/packages/components/src/components/hds/card/container.ts
@@ -5,20 +5,25 @@
import Component from '@glimmer/component';
import { assert } from '@ember/debug';
+
import {
HdsCardBackgroundValues,
HdsCardLevelValues,
HdsCardOverflowValues,
+ HdsCardTagValues,
} from './types.ts';
+
import type {
HdsCardBackground,
HdsCardLevel,
HdsCardOverflow,
+ HdsCardTag,
} from './types.ts';
export const DEFAULT_LEVEL = HdsCardLevelValues.Base;
export const DEFAULT_BACKGROUND = HdsCardBackgroundValues.NeutralPrimary;
export const DEFAULT_OVERFLOW = HdsCardOverflowValues.Visible;
+export const DEFAULT_TAG = HdsCardTagValues.Div;
export const AVAILABLE_LEVELS: string[] = Object.values(HdsCardLevelValues);
export const AVAILABLE_BACKGROUNDS: string[] = Object.values(
HdsCardBackgroundValues
@@ -26,6 +31,7 @@ export const AVAILABLE_BACKGROUNDS: string[] = Object.values(
export const AVAILABLE_OVERFLOWS: string[] = Object.values(
HdsCardOverflowValues
);
+export const AVAILABLE_TAGS: string[] = Object.values(HdsCardTagValues);
export interface HdsCardContainerSignature {
Args: {
@@ -35,22 +41,16 @@ export interface HdsCardContainerSignature {
background?: HdsCardBackground;
hasBorder?: boolean;
overflow?: HdsCardOverflow;
+ tag?: HdsCardTag;
};
Blocks: {
default: [];
};
- Element: HTMLDivElement;
+ Element: HTMLElement;
}
export default class HdsCardContainer extends Component {
- /**
- * Sets the "elevation" level for the component
- * Accepted values: base, mid, high
- *
- * @param level
- * @type {HdsCardLevel}
- * @default 'base'
- */
+ // Sets the "elevation" level for the component
get level(): HdsCardLevel {
const { level = DEFAULT_LEVEL } = this.args;
@@ -64,13 +64,7 @@ export default class HdsCardContainer extends Component
+
Background
@@ -71,6 +72,7 @@
Overflow
+
@@ -92,4 +94,24 @@
+ Tag
+
+
+
\ No newline at end of file
diff --git a/showcase/tests/integration/components/hds/card/container-test.js b/showcase/tests/integration/components/hds/card/container-test.js
index dfb42d85420..51c7eee3346 100644
--- a/showcase/tests/integration/components/hds/card/container-test.js
+++ b/showcase/tests/integration/components/hds/card/container-test.js
@@ -79,6 +79,26 @@ module('Integration | Component | hds/card/container', function (hooks) {
.hasClass('hds-card__container--overflow-hidden');
});
+ // TAG
+
+ test(`it should render a div if no @tag prop is declared and it should not have a role`, async function (assert) {
+ await render(hbs``);
+ assert
+ .dom('#test-card-container')
+ .hasTagName('div')
+ .doesNotHaveAttribute('role');
+ });
+
+ test(`it should render an li if specified in the @tag prop and it should have the correct role`, async function (assert) {
+ await render(
+ hbs``
+ );
+ assert
+ .dom('#test-card-container')
+ .hasTagName('li')
+ .hasAttribute('role', 'listitem');
+ });
+
// ASSERTIONS
test('it should throw an assertion if an incorrect value for @level is provided', async function (assert) {
@@ -117,4 +137,18 @@ module('Integration | Component | hds/card/container', function (hooks) {
throw new Error(errorMessage);
});
});
+
+ // If a tag other than div or li is passed, it should throw an assertion
+ test('it should throw an assertion if an incorrect value for @tag is provided', async function (assert) {
+ const errorMessage =
+ '@tag for "Hds::Card::Container" must be one of the following: div, li; received: section';
+ assert.expect(2);
+ setupOnerror(function (error) {
+ assert.strictEqual(error.message, `Assertion Failed: ${errorMessage}`);
+ });
+ await render(hbs``);
+ assert.throws(function () {
+ throw new Error(errorMessage);
+ });
+ });
});