diff --git a/.changeset/empty-bikes-pay.md b/.changeset/empty-bikes-pay.md
new file mode 100644
index 0000000000..0e2c0e6bc1
--- /dev/null
+++ b/.changeset/empty-bikes-pay.md
@@ -0,0 +1,5 @@
+---
+'@solid-design-system/components': minor
+---
+
+Added a new attribute `stacked` to the `sd-navigation-item` component that enables a new vertical stacked variant to the horizontal layout.
\ No newline at end of file
diff --git a/.changeset/rich-cases-sleep.md b/.changeset/rich-cases-sleep.md
new file mode 100644
index 0000000000..58c947e0c8
--- /dev/null
+++ b/.changeset/rich-cases-sleep.md
@@ -0,0 +1,5 @@
+---
+'@solid-design-system/docs': minor
+---
+
+Added documentation for the new `stacked` attribute for the `sd-navigation-item` component.
\ No newline at end of file
diff --git a/packages/components/src/components/navigation-item/navigation-item.ts b/packages/components/src/components/navigation-item/navigation-item.ts
index caec64efb9..1ea7ba8a4c 100644
--- a/packages/components/src/components/navigation-item/navigation-item.ts
+++ b/packages/components/src/components/navigation-item/navigation-item.ts
@@ -71,6 +71,9 @@ export default class SdNavigationItem extends SolidElement {
/** Disables the navigation item. */
@property({ type: Boolean, reflect: true }) disabled = false;
+ /** Stacks the navigation-item in a vertical layout. Only used if `vertical` is false. */
+ @property({ type: Boolean, reflect: true }) stacked = false;
+
/** Appends a chevron to the right side of a navigation item. Only used if `vertical` is true. */
@property({ type: Boolean, reflect: true }) chevron = false;
@@ -122,6 +125,10 @@ export default class SdNavigationItem extends SolidElement {
);
}
+ private get isStackedHorizontal(): boolean {
+ return !this.vertical && this.stacked;
+ }
+
private handleClickButton(event: MouseEvent) {
if (this.disabled) {
event.preventDefault();
@@ -197,7 +204,7 @@ export default class SdNavigationItem extends SolidElement {
children: this.hasSlotController.test('children')
};
- const horizontalPadding = this.vertical ? 'py-3' : 'py-2';
+ const horizontalPadding = this.vertical ? 'py-3' : this.isStackedHorizontal ? 'pt-1 pb-1' : 'py-2';
/* eslint-disable lit/no-invalid-html */
/* eslint-disable lit/binding-positions */
@@ -206,14 +213,21 @@ export default class SdNavigationItem extends SolidElement {
part="base"
class=${cx(
'flex items-center cursor-pointer relative focus-visible:focus-outline group hover:bg-neutral-200 transition-colors duration-fast ease-in-out min-h-[48px] navigable-border-radius',
- { md: 'navigable-font-size', lg: 'text-lg', sm: 'text-[14px]' }[this.size],
+ this.isStackedHorizontal
+ ? 'text-xs leading-4.5'
+ : { md: 'navigable-font-size', lg: 'text-lg', sm: 'text-[14px]' }[this.size],
this.disabled ? 'text-neutral-500 pointer-events-none' : 'sd-navigation-item-color-text',
- this.current ? 'font-bold sd-navigation-item--current-color-text' : 'choice-control-font-weight',
+ this.current && !this.disabled && 'sd-navigation-item--current-color-text',
+ this.current && !this.isStackedHorizontal && 'font-bold',
+ !this.current && !this.isStackedHorizontal && 'choice-control-font-weight',
!isAccordion && 'w-full',
this.divider && this.vertical && 'mt-0.25',
- !this.vertical && 'inline-flex items-center',
+ !this.vertical &&
+ (this.isStackedHorizontal
+ ? 'inline-flex flex-col items-center justify-center text-center rounded-full wrap'
+ : 'inline-flex items-center'),
!this.separated && 'hover:bg-neutral-200 group transition-colors duration-fast ease-in-out min-h-[48px]',
- isIconOnly ? 'justify-center aspect-square p-3' : 'px-4'
+ isIconOnly ? 'justify-center aspect-square p-3' : this.isStackedHorizontal ? 'px-8' : 'px-4'
)}
aria-current=${ifDefined(this.current ? 'page' : undefined)}
aria-disabled=${this.disabled}
@@ -230,18 +244,25 @@ export default class SdNavigationItem extends SolidElement {
+
`
: ''
}
-
-
+
+
${
this.chevron || (slots['children'] && this.vertical && !this.separated)
@@ -352,6 +390,10 @@ export default class SdNavigationItem extends SolidElement {
@apply block;
}
+ :host([stacked]:not([vertical])) ::slotted(sd-icon) {
+ @apply w-6 h-6;
+ }
+
/* TODO clean sd-navigation-item--current-color-text and delete this class from line 210 (breaking change) */
.sd-navigation-item--current-color-text {
color: rgb(var(--sd-navigation-item--current-color-text, var(--sd-navigation-item-color-text)));
diff --git a/packages/docs/src/stories/components/navigation-item.mdx b/packages/docs/src/stories/components/navigation-item.mdx
index d01f912b4a..f6da494809 100644
--- a/packages/docs/src/stories/components/navigation-item.mdx
+++ b/packages/docs/src/stories/components/navigation-item.mdx
@@ -38,6 +38,7 @@ Used to facilitate seamless page transitions and help users orient themselves wi
- Populate an [sd-header](./?path=/docs/components-sd-header--docs) navigation bar at the top of a page, helping users easily access different sections.
- Implement navigation items in a sidebar for a more detailed and hierarchical navigation structure.
+- Add stacked navigation items to a bottom bar used in mobile or web apps.
### Usage Guidelines
diff --git a/packages/docs/src/stories/components/navigation-item.stories.ts b/packages/docs/src/stories/components/navigation-item.stories.ts
index 724381d9f8..01d5a571ec 100644
--- a/packages/docs/src/stories/components/navigation-item.stories.ts
+++ b/packages/docs/src/stories/components/navigation-item.stories.ts
@@ -84,6 +84,19 @@ export const Disabled = {
render: () => html` Disabled Navigation `
};
+/**
+ * Use the ”stacked” attribute to create a stacked layout of the navigation item with icon.
+ */
+
+export const Stacked = {
+ render: () => html`
+
+
+ Navigation
+
+ `
+};
+
/**
* Use the `divider` attribute to add a divider above the navigation item.
*
diff --git a/packages/docs/src/stories/components/navigation-item.test.stories.ts b/packages/docs/src/stories/components/navigation-item.test.stories.ts
index e945de363f..12759672ea 100644
--- a/packages/docs/src/stories/components/navigation-item.test.stories.ts
+++ b/packages/docs/src/stories/components/navigation-item.test.stories.ts
@@ -52,20 +52,33 @@ export const Default = {
}
};
-export const Current = {
- name: 'Variant x Current',
- render: (args: any) =>
- generateTemplate({
- args,
- axis: {
- x: { type: 'attribute', name: 'vertical' },
- y: { type: 'attribute', name: 'current' }
- }
- })
+export const OrientationAndCurrent = {
+ name: 'Orientation x Current',
+ render: (args: any) => {
+ return html`
+ ${generateTemplate({
+ args,
+ axis: {
+ x: { type: 'attribute', name: 'vertical' },
+ y: { type: 'attribute', name: 'current' }
+ }
+ })}
+ ${generateTemplate({
+ axis: {
+ y: { type: 'attribute', name: 'current' }
+ },
+ constants: [
+ { type: 'attribute', name: 'stacked', value: true },
+ { type: 'slot', name: 'default', value: 'Navigation' }
+ ],
+ args
+ })}
+ `;
+ }
};
-export const Variants = {
- name: 'Variant × Size',
+export const OrientationAndSize = {
+ name: 'Orientation × Size',
render: (args: any) => {
return html`
${generateTemplate({
@@ -110,6 +123,31 @@ export const Variants = {
}
};
+export const OrientationAndLink = {
+ name: 'Orientation × Link',
+ render: (args: any) => {
+ return html`
+ ${generateTemplate({
+ axis: {
+ x: { type: 'attribute', name: 'href', values: ['', '#'] },
+ y: { type: 'attribute', name: 'vertical' }
+ },
+ args
+ })}
+ ${generateTemplate({
+ axis: {
+ y: { type: 'attribute', name: 'href', values: ['', '#'] }
+ },
+ constants: [
+ { type: 'attribute', name: 'stacked', value: true },
+ { type: 'slot', name: 'default', value: 'Navigation' }
+ ],
+ args
+ })}
+ `;
+ }
+};
+
export const Disabled = {
name: 'Disabled',
render: (args: any) => {
@@ -143,36 +181,64 @@ export const Disabled = {
],
args
})}
- `;
- }
-};
-
-export const VerticalAndCurrent = {
- name: 'Vertical × Current',
- render: (args: any) => {
- return html`
${generateTemplate({
axis: {
- x: { type: 'attribute', name: 'vertical' },
y: { type: 'attribute', name: 'current' }
},
+ options: {
+ title: 'Stacked (Horizontal)'
+ },
+ constants: [
+ { type: 'attribute', name: 'disabled', value: true },
+ { type: 'attribute', name: 'stacked', value: true },
+ { type: 'slot', name: 'default', value: 'Navigation' }
+ ],
args
})}
`;
}
};
-export const VerticalAndLink = {
- name: 'Vertical × Link',
+export const Stacked = {
+ name: 'Stacked',
render: (args: any) => {
+ const cases = [
+ {
+ title: 'Default',
+ slot: 'Navigation'
+ },
+ {
+ title: 'Short Navigation',
+ slot: 'Nav'
+ },
+ {
+ title: 'Large Navigation',
+ slot: 'Large Navigation'
+ }
+ ];
+
return html`
- ${generateTemplate({
- axis: {
- x: { type: 'attribute', name: 'href', values: ['', '#'] },
- y: { type: 'attribute', name: 'vertical' }
- },
- args
- })}
+ ${cases.map(
+ c => html`
+ ${generateTemplate({
+ axis: {
+ y: { type: 'attribute', name: 'current' }
+ },
+ options: {
+ title: c.title
+ },
+ constants: [
+ { type: 'attribute', name: 'stacked', value: true },
+ {
+ type: 'slot',
+ name: 'default',
+ value: c.slot
+ }
+ ],
+ args
+ })}
+ `
+ )}
`;
}
};
@@ -420,14 +486,14 @@ export const Mouseless = {
export const Combination = generateScreenshotStory([
Default,
- Current,
- Variants,
+ OrientationAndCurrent,
+ OrientationAndSize,
+ OrientationAndLink,
Disabled,
+ Stacked,
Parts,
Chevron,
IndentedRelaxed,
- VerticalAndCurrent,
- VerticalAndLink,
Separated,
Slots,
Mouseless