Repository: melt-ui/melt-ui
Pull request #1004 (2024-02-23 01:50:17)

fix(Toolbar): set correct tabindex for buttons and links
At present, the tabindex attribute of toolbar items is initialized only for group items, never for simple buttons or links.

As a result, when there is no group item, or the first item is a button/link, the toolbar becomes inaccessible by keyboard navigation.

This patch fixes the problem and introduces a comprehensive suite of regression tests, both by changing the order of items and by removing group items entirely.

changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: 0653c36dd322c404a96c36e00204843b5147c3c5

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name            | Type  |
| --------------- | ----- |
| @melt-ui/svelte | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/fbbdev/melt-ui/new/toolbar-fix?filename=.changeset/forty-carpets-mate.md&value=---%0A%22%40melt-ui%2Fsvelte%22%3A%20patch%0A---%0A%0Afix(Toolbar)%3A%20set%20correct%20tabindex%20for%20buttons%20and%20links%0A)



Patch:
diff --git a/.changeset/proud-pigs-pump.md b/.changeset/proud-pigs-pump.md
new file mode 100644
index 00000000..8c80fc5d
--- /dev/null
+++ b/.changeset/proud-pigs-pump.md
@@ -0,0 +1,5 @@
+---
+'@melt-ui/svelte': patch
+---
+
+Toolbar: set correct tabindex for buttons and links
diff --git a/src/docs/components/tooltip.svelte b/src/docs/components/tooltip.svelte
index a0cdb4d7..be92e102 100644
--- a/src/docs/components/tooltip.svelte
+++ b/src/docs/components/tooltip.svelte
@@ -36,7 +36,7 @@
 	[data-melt-tooltip-content] {
 		opacity: 0;
 		visibility: hidden;
-		transition: 150ms ease;
+		transition: opacity 150ms ease;
 
 		&[data-open] {
 			opacity: 1;
diff --git a/src/lib/builders/toolbar/create.ts b/src/lib/builders/toolbar/create.ts
index 11641e0f..051ab1c4 100644
--- a/src/lib/builders/toolbar/create.ts
+++ b/src/lib/builders/toolbar/create.ts
@@ -48,9 +48,10 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 			({
 				role: 'button',
 				type: 'button',
-				tabIndex: -1,
 			} as const),
 		action: (node: HTMLElement): MeltActionReturn<ToolbarEvents['button']> => {
+			setNodeTabIndex(node);
+
 			const unsub = addMeltEventListener(node, 'keydown', handleKeyDown);
 
 			return {
@@ -63,10 +64,10 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 		returned: () =>
 			({
 				role: 'link',
-				'data-melt-toolbar-item': '',
-				tabIndex: -1,
 			} as const),
 		action: (node: HTMLElement): MeltActionReturn<ToolbarEvents['link']> => {
+			setNodeTabIndex(node);
+
 			const unsub = addMeltEventListener(node, 'keydown', handleKeyDown);
 
 			return {
@@ -149,6 +150,8 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 				};
 			},
 			action: (node: HTMLElement): MeltActionReturn<ToolbarEvents['item']> => {
+				setNodeTabIndex(node);
+
 				function getNodeProps() {
 					const itemValue = node.dataset.value;
 					const disabled = node.dataset.disabled === 'true';
@@ -172,17 +175,6 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 					});
 				}
 
-				const parentToolbar = node.closest('[data-melt-toolbar]');
-				if (!isHTMLElement(parentToolbar)) return {};
-
-				const items = getToolbarItems(parentToolbar);
-
-				if (items[0] === node) {
-					node.tabIndex = 0;
-				} else {
-					node.tabIndex = -1;
-				}
-
 				const unsub = executeCallbacks(
 					addMeltEventListener(node, 'click', () => {
 						handleValueUpdate();
@@ -224,12 +216,6 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 		};
 	};
 
-	function getToolbarItems(element: HTMLElement) {
-		return Array.from(
-			element.querySelectorAll(`${selector('item')}, ${selector('button')}`)
-		).filter((el): el is HTMLElement => isHTMLElement(el));
-	}
-
 	function handleKeyDown(e: KeyboardEvent) {
 		const $orientation = orientation.get();
 		const $loop = loop.get();
@@ -250,9 +236,7 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 		const root = el.closest('[data-melt-toolbar]');
 		if (!isHTMLElement(root)) return;
 
-		const items = Array.from(
-			root.querySelectorAll(`${selector('item')}, ${selector('button')}`)
-		).filter((el): el is HTMLElement => isHTMLElement(el));
+		const items = getToolbarItems(root);
 
 		const currentIndex = items.indexOf(el);
 
@@ -294,3 +278,30 @@ export const createToolbar = (props?: CreateToolbarProps) => {
 		options,
 	};
 };
+
+/**
+ * Sets the appropriate tabIndex for the node based on its position in the
+ * parent toolbar.
+ */
+function setNodeTabIndex(node: HTMLElement) {
+	const parentToolbar = node.closest('[data-melt-toolbar]');
+
+	if (!isHTMLElement(parentToolbar)) return;
+
+	const items = getToolbarItems(parentToolbar);
+
+	if (items[0] === node) {
+		node.tabIndex = 0;
+	} else {
+		node.tabIndex = -1;
+	}
+}
+
+/**
+ * Returns an array of all toolbar items within the given element.
+ */
+function getToolbarItems(element: HTMLElement) {
+	return Array.from(
+		element.querySelectorAll(`${selector('item')}, ${selector('button')}, ${selector('link')}`)
+	).filter((el): el is HTMLElement => isHTMLElement(el));
+}
diff --git a/src/routes/(landing-ui)/search.svelte b/src/routes/(landing-ui)/search.svelte
index 6c8484a0..f3849490 100644
--- a/src/routes/(landing-ui)/search.svelte
+++ b/src/routes/(landing-ui)/search.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
 	import { goto } from '$app/navigation';
 	import { Tooltip } from '$docs/components/index.js';
-	import { createCombobox, createDialog, melt } from '$lib/index.js';
+	import { createCombobox, createDialog, createSync, melt } from '$lib/index.js';
 	import { CornerDownRight, LoaderIcon, Search as SearchIcon } from '$icons/index.js';
 	import { onMount } from 'svelte';
 	import type { Pagefind, PagefindSearchFragment, PagefindSubResult } from '../../pagefind.js';
@@ -35,9 +35,13 @@
 			}
 			return undefined;
 		},
-		forceVisible: true,
 		preventScroll: false,
 		highlightOnHover: false,
+		portal: null,
+		onOutsideClick() {
+			open.set(false);
+			cbOpen.set(false);
+		},
 	});
 
 	let comboboxInput: HTMLInputElement | null = null;
diff --git a/src/routes/repro/+page.ts b/src/routes/repro/+page.ts
index b88b1711..28882678 100644
--- a/src/routes/repro/+page.ts
+++ b/src/routes/repro/+page.ts
@@ -2,5 +2,5 @@ import { redirect } from '@sveltejs/kit';
 import type { PageLoad } from './$types.js';
 
 export const load: PageLoad = async () => {
-	redirect(303, 'https://stackblitz.com/github/melt-ui/playground');
+	redirect(303, 'https://stackblitz.com/github/melt-ui/template');
 };


Test patch:
diff --git a/src/tests/toolbar/Toolbar.spec.ts b/src/tests/toolbar/Toolbar.spec.ts
index 67bdb009..1f93f658 100644
--- a/src/tests/toolbar/Toolbar.spec.ts
+++ b/src/tests/toolbar/Toolbar.spec.ts
@@ -6,6 +6,7 @@ import { describe } from 'vitest';
 import ToolbarTest from './ToolbarTest.svelte';
 import { writable } from 'svelte/store';
 import { tick } from 'svelte';
+import { type CreateToolbarProps } from '$lib/index.js';
 
 const group1Items = ['item-1', 'item-2', 'item-3'];
 const group2Items = ['item-4', 'item-5', 'item-6'];
@@ -13,8 +14,15 @@ const tbItems = [...group1Items, ...group2Items];
 
 const tbLinks = ['link-1'];
 const tbButtons = ['button-1'];
+const tbLinksAndButtons = [...tbLinks, ...tbButtons];
+const tbButtonsAndLinks = [...tbButtons, ...tbLinks];
 
 const allToolbarItems = [...tbItems, ...tbLinks, ...tbButtons];
+const allToolbarItemsLinksFirst = [...tbLinks, ...tbItems, ...tbButtons];
+const allToolbarItemsButtonsFirst = [...tbButtons, ...tbItems, ...tbLinks];
+
+const horizontal: CreateToolbarProps['orientation'] = 'horizontal';
+const vertical: CreateToolbarProps['orientation'] = 'vertical';
 
 describe('Toolbar', () => {
 	test('has no accessibility violations', async () => {
@@ -22,62 +30,287 @@ describe('Toolbar', () => {
 		expect(await axe(container)).toHaveNoViolations();
 	});
 
-	test("tab enters toolbar but doesn't navigate between items", async () => {
+	test.each([
+		{ desc: '', props: {}, items: allToolbarItems },
+		{
+			desc: 'first item is a link',
+			props: { linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'first item is a button',
+			props: { buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'no group items, first item is a link',
+			props: { linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'no group items, first item is a button',
+			props: { linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+	])("tab enters toolbar but doesn't navigate between items - $desc", async ({ props, items }) => {
 		const user = userEvent.setup();
-		const { getByTestId } = render(ToolbarTest);
+		const { getByTestId } = render(ToolbarTest, props);
 
 		await user.tab();
-		expect(getByTestId('item-1')).toHaveFocus();
+		expect(getByTestId(items[0])).toHaveFocus();
 		await user.tab();
-		expect(getByTestId('item-2')).not.toHaveFocus();
+		expect(getByTestId(items[1])).not.toHaveFocus();
 		await user.tab({ shift: true });
-		expect(getByTestId('item-1')).toHaveFocus();
+		expect(getByTestId(items[0])).toHaveFocus();
 		await user.tab({ shift: true });
-		expect(getByTestId('item-1')).not.toHaveFocus();
+		expect(getByTestId(items[0])).not.toHaveFocus();
 	});
 
-	test('arrow keys navigate between items', async () => {
+	test.each([
+		{ desc: 'horizontal', props: { orientation: horizontal }, items: allToolbarItems },
+		{ desc: 'vertical', props: { orientation: vertical }, items: allToolbarItems },
+		{
+			desc: 'horizontal, first item is a link',
+			props: { orientation: horizontal, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'vertical, first item is a link',
+			props: { orientation: vertical, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'horizontal, first item is a button',
+			props: { orientation: horizontal, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'vertical, first item is a button',
+			props: { orientation: vertical, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a link',
+			props: { orientation: horizontal, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'vertical, no group items, first item is a link',
+			props: { orientation: vertical, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a button',
+			props: { orientation: horizontal, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+		{
+			desc: 'vertical, no group items, first item is a button',
+			props: { orientation: vertical, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+	])('arrow keys navigate between items - $desc', async ({ props, items }) => {
 		const user = userEvent.setup();
-		const { getByTestId } = render(ToolbarTest);
+		const { getByTestId } = render(ToolbarTest, props);
 
-		await user.tab();
+		const nextKey = `{${props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN}}`;
+		const prevKey = `{${props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP}}`;
+
+		const reversedItems = [...items].reverse();
 
-		const reversedItems = [...allToolbarItems].reverse();
+		await user.tab();
 
-		for (const item of allToolbarItems) {
+		for (const item of items) {
 			expect(getByTestId(item)).toHaveFocus();
-			await user.keyboard(`{${kbd.ARROW_RIGHT}}`);
+			await user.keyboard(nextKey);
 		}
 
 		for (const item of reversedItems) {
 			expect(getByTestId(item)).toHaveFocus();
-			await user.keyboard(`{${kbd.ARROW_LEFT}}`);
+			await user.keyboard(prevKey);
 		}
 	});
 
-	test('home and end keys focus first and last items - horizontal', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(ToolbarTest);
-
-		await user.tab();
-		const firstItem = getByTestId('item-1');
-		const lastItem = getByTestId('button-1');
-		expect(firstItem).toHaveFocus();
-		await user.keyboard(`{${kbd.END}}`);
-		expect(lastItem).toHaveFocus();
-		await user.keyboard(`{${kbd.HOME}}`);
-		expect(firstItem).toHaveFocus();
-	});
-
-	test('home and end keys focus first and last items - vertical', async () => {
+	test.each([
+		{ desc: 'horizontal', props: { orientation: horizontal }, items: allToolbarItems },
+		{ desc: 'vertical', props: { orientation: vertical }, items: allToolbarItems },
+		{
+			desc: 'horizontal, first item is a link',
+			props: { orientation: horizontal, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'vertical, first item is a link',
+			props: { orientation: vertical, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'horizontal, first item is a button',
+			props: { orientation: horizontal, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'vertical, first item is a button',
+			props: { orientation: vertical, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a link',
+			props: { orientation: horizontal, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'vertical, no group items, first item is a link',
+			props: { orientation: vertical, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a button',
+			props: { orientation: horizontal, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+		{
+			desc: 'vertical, no group items, first item is a button',
+			props: { orientation: vertical, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+	])(
+		'arrow key navigation loops around when looping is enabled - $desc',
+		async ({ props, items }) => {
+			const user = userEvent.setup();
+			const { getByTestId } = render(ToolbarTest, { loop: true, ...props });
+
+			const nextKey = `{${props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN}}`;
+			const prevKey = `{${props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP}}`;
+
+			await user.tab();
+			const firstItem = getByTestId(items[0]);
+			const lastItem = getByTestId(items[items.length - 1]);
+			expect(firstItem).toHaveFocus();
+			await user.keyboard(prevKey);
+			expect(lastItem).toHaveFocus();
+			await user.keyboard(nextKey);
+			expect(firstItem).toHaveFocus();
+		}
+	);
+
+	test.each([
+		{ desc: 'horizontal', props: { orientation: horizontal }, items: allToolbarItems },
+		{ desc: 'vertical', props: { orientation: vertical }, items: allToolbarItems },
+		{
+			desc: 'horizontal, first item is a link',
+			props: { orientation: horizontal, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'vertical, first item is a link',
+			props: { orientation: vertical, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'horizontal, first item is a button',
+			props: { orientation: horizontal, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'vertical, first item is a button',
+			props: { orientation: vertical, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a link',
+			props: { orientation: horizontal, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'vertical, no group items, first item is a link',
+			props: { orientation: vertical, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a button',
+			props: { orientation: horizontal, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+		{
+			desc: 'vertical, no group items, first item is a button',
+			props: { orientation: vertical, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+	])(
+		'arrow key navigation does not loop around when looping is disabled - $desc',
+		async ({ props, items }) => {
+			const user = userEvent.setup();
+			const { getByTestId } = render(ToolbarTest, { loop: false, ...props });
+
+			const nextKey = `{${props.orientation === horizontal ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN}}`;
+			const prevKey = `{${props.orientation === horizontal ? kbd.ARROW_LEFT : kbd.ARROW_UP}}`;
+
+			const firstItem = getByTestId(items[0]);
+			const lastItem = getByTestId(items[items.length - 1]);
+
+			firstItem.focus();
+			expect(firstItem).toHaveFocus();
+			await user.keyboard(prevKey);
+			expect(firstItem).toHaveFocus();
+
+			lastItem.focus();
+			expect(lastItem).toHaveFocus();
+			await user.keyboard(nextKey);
+			expect(lastItem).toHaveFocus();
+		}
+	);
+
+	test.each([
+		{ desc: 'horizontal', props: { orientation: horizontal }, items: allToolbarItems },
+		{ desc: 'vertical', props: { orientation: vertical }, items: allToolbarItems },
+		{
+			desc: 'horizontal, first item is a link',
+			props: { orientation: horizontal, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'vertical, first item is a link',
+			props: { orientation: vertical, linksFirst: true },
+			items: allToolbarItemsLinksFirst,
+		},
+		{
+			desc: 'horizontal, first item is a button',
+			props: { orientation: horizontal, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'vertical, first item is a button',
+			props: { orientation: vertical, buttonsFirst: true },
+			items: allToolbarItemsButtonsFirst,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a link',
+			props: { orientation: horizontal, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'vertical, no group items, first item is a link',
+			props: { orientation: vertical, linksButtonsOnly: true, linksFirst: true },
+			items: tbLinksAndButtons,
+		},
+		{
+			desc: 'horizontal, no group items, first item is a button',
+			props: { orientation: horizontal, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+		{
+			desc: 'vertical, no group items, first item is a button',
+			props: { orientation: vertical, linksButtonsOnly: true, buttonsFirst: true },
+			items: tbButtonsAndLinks,
+		},
+	])('home and end keys focus first and last items - $desc', async ({ props, items }) => {
 		const user = userEvent.setup();
-		const { getByTestId } = render(ToolbarTest, {
-			orientation: 'vertical',
-		});
+		const { getByTestId } = render(ToolbarTest, props);
 
 		await user.tab();
-		const firstItem = getByTestId('item-1');
-		const lastItem = getByTestId('button-1');
+		const firstItem = getByTestId(items[0]);
+		const lastItem = getByTestId(items[items.length - 1]);
 		expect(firstItem).toHaveFocus();
 		await user.keyboard(`{${kbd.END}}`);
 		expect(lastItem).toHaveFocus();
@@ -157,27 +390,6 @@ describe('Toolbar', () => {
 		expect(group2OnItems.length).toBe(1);
 	});
 
-	test('orientation changes keyboard nav', async () => {
-		const user = userEvent.setup();
-		const { getByTestId } = render(ToolbarTest, {
-			orientation: 'vertical',
-		});
-
-		await user.tab();
-
-		const reversedItems = [...allToolbarItems].reverse();
-
-		for (const item of allToolbarItems) {
-			expect(getByTestId(item)).toHaveFocus();
-			await user.keyboard(`{${kbd.ARROW_DOWN}}`);
-		}
-
-		for (const item of reversedItems) {
-			expect(getByTestId(item)).toHaveFocus();
-			await user.keyboard(`{${kbd.ARROW_UP}}`);
-		}
-	});
-
 	test('default value sets initial pressed/checked items', async () => {
 		const { getByTestId } = render(ToolbarTest, {
 			orientation: 'vertical',
diff --git a/src/tests/toolbar/ToolbarTest.svelte b/src/tests/toolbar/ToolbarTest.svelte
index 0af7dd03..840c50ab 100644
--- a/src/tests/toolbar/ToolbarTest.svelte
+++ b/src/tests/toolbar/ToolbarTest.svelte
@@ -25,6 +25,10 @@
 		value: undefined,
 	};
 
+	export let linksFirst = false;
+	export let buttonsFirst = false;
+	export let linksButtonsOnly = false;
+
 	const {
 		elements: { root, button, link, separator },
 		builders: { createToolbarGroup },
@@ -44,19 +48,31 @@
 
 <main>
 	<div use:melt={$root} data-testid="root">
-		<div use:melt={$fontGroup} data-testid="group-1">
-			<button use:melt={$fontItem('item-1')} data-testid="item-1"> item-1 </button>
-			<button use:melt={$fontItem('item-2')} data-testid="item-2"> item-2 </button>
-			<button use:melt={$fontItem('item-3')} data-testid="item-3"> item-3 </button>
-		</div>
-		<div use:melt={$separator} />
-		<div use:melt={$alignGroup} data-testid="group-2">
-			<button use:melt={$alignItem('item-4')} data-testid="item-4"> item-4 </button>
-			<button use:melt={$alignItem('item-5')} data-testid="item-5"> item-5 </button>
-			<button use:melt={$alignItem('item-6')} data-testid="item-6"> item-6</button>
-		</div>
-		<div use:melt={$separator} />
-		<a href="/" use:melt={$link} data-testid="link-1"> link-1 </a>
-		<button use:melt={$button} data-testid="button-1">button-1</button>
+		{#if linksFirst}
+			<a href="/" use:melt={$link} data-testid="link-1"> link-1 </a>
+		{/if}
+		{#if buttonsFirst}
+			<button use:melt={$button} data-testid="button-1"> button-1 </button>
+		{/if}
+		{#if !linksButtonsOnly}
+			<div use:melt={$fontGroup} data-testid="group-1">
+				<button use:melt={$fontItem('item-1')} data-testid="item-1"> item-1 </button>
+				<button use:melt={$fontItem('item-2')} data-testid="item-2"> item-2 </button>
+				<button use:melt={$fontItem('item-3')} data-testid="item-3"> item-3 </button>
+			</div>
+			<div use:melt={$separator} />
+			<div use:melt={$alignGroup} data-testid="group-2">
+				<button use:melt={$alignItem('item-4')} data-testid="item-4"> item-4 </button>
+				<button use:melt={$alignItem('item-5')} data-testid="item-5"> item-5 </button>
+				<button use:melt={$alignItem('item-6')} data-testid="item-6"> item-6</button>
+			</div>
+			<div use:melt={$separator} />
+		{/if}
+		{#if !linksFirst}
+			<a href="/" use:melt={$link} data-testid="link-1"> link-1 </a>
+		{/if}
+		{#if !buttonsFirst}
+			<button use:melt={$button} data-testid="button-1"> button-1 </button>
+		{/if}
 	</div>
 </main>