diff --git a/packages/react-integration/cypress/integration/duallistselectorbasic.spec.ts b/packages/react-integration/cypress/integration/duallistselectorbasic.spec.ts
new file mode 100644
index 00000000000..a540704e558
--- /dev/null
+++ b/packages/react-integration/cypress/integration/duallistselectorbasic.spec.ts
@@ -0,0 +1,108 @@
+describe('Dual List Selector Basic Demo Test', () => {
+ it('Navigate to demo section', () => {
+ cy.visit('http://localhost:3000/dual-list-selector-basic-demo-nav-link');
+ });
+
+ it('Verify existence', () => {
+ cy.get('.pf-v6-c-dual-list-selector').should('exist');
+ });
+
+ it('Verify default aria-labels, status, and titles', () => {
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__title-text').contains('Available options');
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 4 options selected');
+
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(1).should('have.attr', 'aria-label', 'Add all');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button')
+ .eq(0)
+ .should('have.attr', 'aria-label', 'Add selected')
+ .and('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button')
+ .eq(3)
+ .should('have.attr', 'aria-label', 'Remove selected')
+ .and('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button')
+ .eq(2)
+ .should('have.attr', 'aria-label', 'Remove all')
+ .and('have.attr', 'disabled');
+
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__title-text').contains('Chosen options');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 0 options selected');
+ });
+
+ it('Verify default value content', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').first().should('have.value', '');
+ cy.get('.pf-v6-c-dual-list-selector__list li').should('have.length', 4);
+ });
+
+ it('Verify selecting options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('not.exist');
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).and('not.have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('exist');
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(1).click();
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('2 of 4 options selected');
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('have.length', 2);
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('have.length', 1);
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('1 of 4 options selected');
+ });
+
+ it('Verify selecting and choosing options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 3);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(1).click();
+
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(1).should('not.have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).should('not.have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(3).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(2).should('not.have.attr', 'disabled');
+
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('1 of 3 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 1 options selected');
+
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(0).click();
+ cy.get('.pf-v6-c-tooltip').should('exist');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 2);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 2);
+
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 2 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 2 options selected');
+ });
+
+ it('Verify removing all options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(2).click();
+ cy.get('.pf-v6-c-tooltip').should('exist');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 0);
+ });
+
+ it('Verify choosing all options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(1).click();
+ cy.get('.pf-v6-c-tooltip').should('exist');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 0);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 4);
+
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(1).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(3).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(2).should('not.have.attr', 'disabled');
+
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 0 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 4 options selected');
+ });
+
+ it('Verify removing all options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(2).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 0);
+
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(1).should('not.have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(3).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(2).should('have.attr', 'disabled');
+
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 4 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 0 options selected');
+ });
+});
diff --git a/packages/react-integration/cypress/integration/duallistselectortree.spec.ts b/packages/react-integration/cypress/integration/duallistselectortree.spec.ts
new file mode 100644
index 00000000000..a7abf220b2d
--- /dev/null
+++ b/packages/react-integration/cypress/integration/duallistselectortree.spec.ts
@@ -0,0 +1,64 @@
+describe('Dual List Selector Tree Demo Test', () => {
+ it('Navigate to demo section', () => {
+ cy.visit('http://localhost:3000/dual-list-selector-tree-demo-nav-link');
+ });
+
+ it('Verify existence', () => {
+ cy.get('.pf-v6-c-dual-list-selector').should('exist');
+ });
+
+ it('Verify expanding options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 3);
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-v6-c-dual-list-selector__item-toggle').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).should('have.class', 'pf-m-expanded');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 6);
+ });
+
+ it('Verify available search works', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 6);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(0).type('bre');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(0).type('{backspace}{backspace}{backspace}');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 3);
+ });
+
+ it('Verify checkbox selects an option', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).should('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-v6-c-dual-list-selector__item-check').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).should('not.have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 2);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 2);
+ });
+
+ xit('Verify add all filtered options works', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 2);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(0).type('Fru');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 3);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(0).type('{backspace}{backspace}{backspace}');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 1);
+ });
+
+ it('Verify chosen search works', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(1).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(1).type('Pro');
+ cy.get('.pf-v6-c-dual-list-selector__item-toggle').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(1).find('li').should('have.length', 1);
+ });
+
+ xit('Verify remove all filtered options works', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 0);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(2).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 0);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(1).type('{backspace}{backspace}{backspace}');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 3);
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(2).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 0);
+ });
+});
diff --git a/packages/react-integration/cypress/integration/duallistselectorwithactions.spec.ts b/packages/react-integration/cypress/integration/duallistselectorwithactions.spec.ts
new file mode 100644
index 00000000000..35cf7300bb3
--- /dev/null
+++ b/packages/react-integration/cypress/integration/duallistselectorwithactions.spec.ts
@@ -0,0 +1,134 @@
+describe('Dual List Selector deprecated With Actions Demo Test', () => {
+ it('Navigate to demo section', () => {
+ cy.visit('http://localhost:3000/dual-list-selector-with-actions-demo-nav-link');
+ });
+
+ it('Verify existence', () => {
+ cy.get('.pf-v6-c-dual-list-selector').should('exist');
+ });
+
+ it('Verify default value content', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').first().should('have.value', '');
+ cy.get('.pf-v6-c-dual-list-selector__list li').should('have.length', 4);
+ });
+
+ it('Verify custom aria-labels, status, and titles', () => {
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__title-text').contains('Available options');
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 4 options selected');
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__tools-filter input').should(
+ 'have.attr',
+ 'aria-label',
+ 'Search input'
+ );
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__list').should('have.attr', 'aria-labelledby');
+
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button').eq(1).should('have.attr', 'aria-label', 'Add all');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button')
+ .eq(0)
+ .should('have.attr', 'aria-label', 'Add selected')
+ .and('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button')
+ .eq(3)
+ .should('have.attr', 'aria-label', 'Remove selected')
+ .and('have.attr', 'disabled');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item button')
+ .eq(2)
+ .should('have.attr', 'aria-label', 'Remove all')
+ .and('have.attr', 'disabled');
+
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__title-text').contains('Chosen options');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 0 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__tools-filter input').should(
+ 'have.attr',
+ 'aria-label',
+ 'Search input'
+ );
+ });
+
+ it('Verify selecting options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('not.exist');
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('exist');
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('have.length', 2);
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list-item .pf-m-selected').should('have.length', 1);
+ });
+
+ it('Verify selecting and choosing options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(0).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 3);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(0).click();
+
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 2 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 2 options selected');
+
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 2);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 2);
+
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).click();
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('1 of 2 options selected');
+ cy.get('.pf-v6-c-dual-list-selector__list-item').eq(0).click();
+ });
+
+ it('Verify removing all options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(2).click();
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(0).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(1).find('li').should('have.length', 0);
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 4 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 0 options selected');
+ });
+
+ it('Verify choosing all options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(0).find('li').should('have.length', 0);
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(1).find('li').should('have.length', 4);
+ cy.get('.pf-m-available .pf-v6-c-dual-list-selector__status-text').contains('0 of 0 options selected');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__status-text').contains('0 of 4 options selected');
+ });
+
+ it('Verify sort works', () => {
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__list-item').last().contains('Option 4');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__tools-actions button').first().click();
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__list-item').last().contains('Option 1');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__list-item').first().contains('Option 4');
+
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__tools-actions button').first().click();
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__list-item').last().contains('Option 4');
+ cy.get('.pf-m-chosen .pf-v6-c-dual-list-selector__list-item').first().contains('Option 1');
+ });
+
+ it('Verify chosen search works', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(1).type('Option 1');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 1);
+ });
+
+ it('Verify removing all options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input')
+ .eq(1)
+ .type('{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}');
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(2).click();
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(0).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__menu').eq(1).find('li').should('have.length', 0);
+ });
+
+ it('Verify available search works', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 4);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input').eq(0).type('Option 3');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 1);
+ });
+
+ it('Verify adding all filtered options', () => {
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__controls-item').eq(1).click();
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 0);
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(1).find('li').should('have.length', 1);
+ cy.get('.pf-v6-c-dual-list-selector__tools-filter input')
+ .eq(0)
+ .type('{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}');
+ cy.get('.pf-v6-c-dual-list-selector__list').eq(0).find('li').should('have.length', 3);
+ });
+});
diff --git a/packages/react-integration/demo-app-ts/src/Demos.ts b/packages/react-integration/demo-app-ts/src/Demos.ts
index da3c73365c1..19dc20b683f 100644
--- a/packages/react-integration/demo-app-ts/src/Demos.ts
+++ b/packages/react-integration/demo-app-ts/src/Demos.ts
@@ -142,6 +142,21 @@ export const Demos: DemoInterface[] = [
name: 'Dropdown Demo',
componentType: Examples.DropdownDemo
},
+ {
+ id: 'dual-list-selector-basic-demo',
+ name: 'DualListSelector basic Demo',
+ componentType: Examples.DualListSelectorBasicDemo
+ },
+ {
+ id: 'dual-list-selector-tree-demo',
+ name: 'DualListSelector Tree Demo',
+ componentType: Examples.DualListSelectorTreeDemo
+ },
+ {
+ id: 'dual-list-selector-with-actions-demo',
+ name: 'DualListSelector with actions Demo',
+ componentType: Examples.DualListSelectorWithActionsDemo
+ },
{
id: 'dual-list-selector-deprecated-basic-demo',
name: 'DualListSelector deprecated basic Demo',
diff --git a/packages/react-integration/demo-app-ts/src/components/demos/DualListSelectorDemo/DualListSelectorBasicDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/DualListSelectorDemo/DualListSelectorBasicDemo.tsx
new file mode 100644
index 00000000000..784c4c7c96d
--- /dev/null
+++ b/packages/react-integration/demo-app-ts/src/components/demos/DualListSelectorDemo/DualListSelectorBasicDemo.tsx
@@ -0,0 +1,161 @@
+import React from 'react';
+import {
+ DualListSelector,
+ DualListSelectorPane,
+ DualListSelectorList,
+ DualListSelectorListItem,
+ DualListSelectorControlsWrapper,
+ DualListSelectorControl
+} from '@patternfly/react-core';
+import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon';
+import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';
+import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';
+import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';
+
+interface Option {
+ text: string;
+ selected: boolean;
+ isVisible: boolean;
+}
+
+export const DualListSelectorBasicDemo: React.FunctionComponent = () => {
+ const [availableOptions, setAvailableOptions] = React.useState