From 3b03b286cad2170158165315b16ecea1456e3e5b Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Tue, 21 Jul 2026 14:54:27 -0400 Subject: [PATCH 1/2] chore(docs): Replace ActionGroup with ActionList Fixes https://github.com/patternfly/patternfly/issues/8486 Co-authored-by: Cursor --- .../src/components/Form/ActionGroup.tsx | 2 + .../src/components/Form/examples/Form.md | 3 + .../components/Form/examples/FormBasic.tsx | 18 ++++-- .../Form/examples/FormHorizontal.tsx | 18 ++++-- .../Form/examples/FormLimitWidth.tsx | 18 ++++-- .../components/Form/examples/FormState.tsx | 49 ++++++++++------ .../src/components/LoginPage/LoginForm.tsx | 23 ++++++-- .../__snapshots__/LoginForm.test.tsx.snap | 18 +++--- .../SearchInput/AdvancedSearchMenu.tsx | 29 ++++++---- .../__snapshots__/SearchInput.test.tsx.snap | 10 +++- .../demos/Button/examples/ButtonProgress.tsx | 58 +++++++++++-------- .../SearchInputAdvancedComposable.tsx | 30 ++++++---- .../cypress/integration/searchinput.spec.ts | 4 +- 13 files changed, 181 insertions(+), 99 deletions(-) diff --git a/packages/react-core/src/components/Form/ActionGroup.tsx b/packages/react-core/src/components/Form/ActionGroup.tsx index f01e78a3074..402a586a81a 100644 --- a/packages/react-core/src/components/Form/ActionGroup.tsx +++ b/packages/react-core/src/components/Form/ActionGroup.tsx @@ -1,6 +1,7 @@ import styles from '@patternfly/react-styles/css/components/Form/form'; import { css } from '@patternfly/react-styles'; +/** @deprecated Use ActionList, ActionListGroup, and ActionListItem instead. */ export interface ActionGroupProps extends React.HTMLProps { /** Anything that can be rendered as ActionGroup content. */ children?: React.ReactNode; @@ -8,6 +9,7 @@ export interface ActionGroupProps extends React.HTMLProps { className?: string; } +/** @deprecated Use ActionList, ActionListGroup, and ActionListItem instead. */ export const ActionGroup: React.FunctionComponent = ({ children = null, className = '', diff --git a/packages/react-core/src/components/Form/examples/Form.md b/packages/react-core/src/components/Form/examples/Form.md index 8efa6679b1f..5b38dd1e4ef 100644 --- a/packages/react-core/src/components/Form/examples/Form.md +++ b/packages/react-core/src/components/Form/examples/Form.md @@ -6,6 +6,9 @@ cssPrefix: pf-v6-c-form propComponents: [ 'ActionGroup', + 'ActionList', + 'ActionListGroup', + 'ActionListItem', 'Form', 'FormGroup', 'FormGroupLabelHelp', diff --git a/packages/react-core/src/components/Form/examples/FormBasic.tsx b/packages/react-core/src/components/Form/examples/FormBasic.tsx index 93af5d17cb2..e9317a2a2a8 100644 --- a/packages/react-core/src/components/Form/examples/FormBasic.tsx +++ b/packages/react-core/src/components/Form/examples/FormBasic.tsx @@ -5,7 +5,9 @@ import { TextInput, Checkbox, Popover, - ActionGroup, + ActionList, + ActionListGroup, + ActionListItem, Button, Radio, HelperText, @@ -123,10 +125,16 @@ export const FormBasic: React.FunctionComponent = () => { - - - - + + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/Form/examples/FormHorizontal.tsx b/packages/react-core/src/components/Form/examples/FormHorizontal.tsx index aaf4b02b43f..dfa3bc8f71c 100644 --- a/packages/react-core/src/components/Form/examples/FormHorizontal.tsx +++ b/packages/react-core/src/components/Form/examples/FormHorizontal.tsx @@ -7,7 +7,9 @@ import { FormSelect, FormSelectOption, Checkbox, - ActionGroup, + ActionList, + ActionListGroup, + ActionListItem, Button, Radio, HelperText, @@ -112,10 +114,16 @@ export const FormHorizontal: React.FunctionComponent = () => { - - - - + + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx b/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx index ac3cfe2faf2..a1bcd9f1e1a 100644 --- a/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx +++ b/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx @@ -5,7 +5,9 @@ import { TextInput, Checkbox, Popover, - ActionGroup, + ActionList, + ActionListGroup, + ActionListItem, Button, Radio, HelperText, @@ -123,10 +125,16 @@ export const FormLimitWidth: React.FunctionComponent = () => { - - - - + + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/Form/examples/FormState.tsx b/packages/react-core/src/components/Form/examples/FormState.tsx index bf47aa95cac..2245c980cfd 100644 --- a/packages/react-core/src/components/Form/examples/FormState.tsx +++ b/packages/react-core/src/components/Form/examples/FormState.tsx @@ -1,6 +1,8 @@ import { useState } from 'react'; import { - ActionGroup, + ActionList, + ActionListGroup, + ActionListItem, Button, ButtonType, ButtonVariant, @@ -89,25 +91,34 @@ export const FormState = () => { - - - - + if (!values['input-id']) { + setError('input-id', 'Input value is required.'); + } else { + alert(`Form submitted with: \n ${JSON.stringify(values)}`); + } + }} + > + Submit + + + + + + + {formStateExpanded && ( <> diff --git a/packages/react-core/src/components/LoginPage/LoginForm.tsx b/packages/react-core/src/components/LoginPage/LoginForm.tsx index c237e79dc66..e85350e7d4a 100644 --- a/packages/react-core/src/components/LoginPage/LoginForm.tsx +++ b/packages/react-core/src/components/LoginPage/LoginForm.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; -import { Form, FormGroup, ActionGroup, FormHelperText } from '../Form'; +import { Form, FormGroup, FormHelperText } from '../Form'; +import { ActionList, ActionListGroup, ActionListItem } from '../ActionList'; import { TextInput } from '../TextInput'; import { Button } from '../Button'; import { Checkbox } from '../Checkbox'; @@ -147,11 +148,21 @@ export const LoginForm: React.FunctionComponent = ({ /> )} - - - + + + + + + + ); }; diff --git a/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap b/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap index 0238714fa10..90e5bb84227 100644 --- a/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap +++ b/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap @@ -134,13 +134,13 @@ exports[`LoginForm LoginForm with rememberMeLabel 1`] = `
- {!!onClear && ( - - )} - + + + + + + {!!onClear && ( + + + + )} + + diff --git a/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap b/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap index 3d7348cd8cb..c6e4c62e773 100644 --- a/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap +++ b/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap @@ -436,13 +436,13 @@ exports[`SearchInput advanced search with custom attributes 1`] = `
+
+
- + + + + + + + ); }; diff --git a/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx b/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx index 6c784d6e873..606aaa7f3f4 100644 --- a/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx +++ b/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx @@ -1,6 +1,8 @@ import { useEffect, useRef, useState } from 'react'; import { - ActionGroup, + ActionList, + ActionListGroup, + ActionListItem, Button, DatePicker, Form, @@ -290,16 +292,22 @@ export const SearchInputAdvancedComposable: React.FunctionComponent = () => { - - - {!!onClear && ( - - )} - + + + + + + + {!!onClear && ( + + )} + + + diff --git a/packages/react-integration/cypress/integration/searchinput.spec.ts b/packages/react-integration/cypress/integration/searchinput.spec.ts index d522616efcf..5fda7d997c3 100644 --- a/packages/react-integration/cypress/integration/searchinput.spec.ts +++ b/packages/react-integration/cypress/integration/searchinput.spec.ts @@ -62,13 +62,13 @@ describe('Search Input Demo Test', () => { cy.get('#enabled-search .pf-v6-c-form-control > input').eq(1).should('have.value', 'hi'); cy.get('#enabled-search .pf-v6-c-form-control > input').eq(2).should('have.value', 'another test'); - cy.get('#enabled-search .pf-v6-c-form__actions button').eq(1).click({ force: true }); + cy.get('#enabled-search .pf-v6-c-action-list button').eq(1).click({ force: true }); cy.get('#enabled-search .pf-v6-c-text-input-group__text-input').should('have.value', ''); cy.get('#enabled-search .pf-v6-c-form-control > input').eq(1).should('have.value', ''); cy.get('#enabled-search .pf-v6-c-form-control > input').eq(2).should('have.value', ''); cy.get('#enabled-search .pf-v6-c-form-control > input').eq(0).type('test'); - cy.get('#enabled-search .pf-v6-c-form__actions button').eq(0).click({ force: true }); + cy.get('#enabled-search .pf-v6-c-action-list button').eq(0).click({ force: true }); cy.get('#enabled-search .pf-v6-c-form input').should('not.exist'); cy.get('#enabled-search .pf-v6-c-text-input-group__text-input').should('have.value', 'username:test'); }); From b82d4cd74022614c3caa78151f8599ba4a32a012 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Fri, 24 Jul 2026 11:45:57 -0400 Subject: [PATCH 2/2] Add form group wrapper from Core --- .../src/components/Form/ActionGroup.tsx | 4 +- .../src/components/Form/FormGroup.tsx | 5 +- .../Form/__tests__/FormGroup.test.tsx | 9 ++ .../__snapshots__/FormGroup.test.tsx.snap | 18 +-- .../components/Form/examples/FormBasic.tsx | 22 +-- .../Form/examples/FormHorizontal.tsx | 22 +-- .../Form/examples/FormLimitWidth.tsx | 22 +-- .../components/Form/examples/FormState.tsx | 56 +++---- .../src/components/LoginPage/LoginForm.tsx | 32 ++-- .../__snapshots__/LoginForm.test.tsx.snap | 143 +++++++++++------- .../SearchInput/AdvancedSearchMenu.tsx | 28 ++-- .../__snapshots__/SearchInput.test.tsx.snap | 56 ++++--- .../demos/Button/examples/ButtonProgress.tsx | 54 +++---- .../SearchInputAdvancedComposable.tsx | 32 ++-- 14 files changed, 286 insertions(+), 217 deletions(-) diff --git a/packages/react-core/src/components/Form/ActionGroup.tsx b/packages/react-core/src/components/Form/ActionGroup.tsx index 402a586a81a..45ed3307d31 100644 --- a/packages/react-core/src/components/Form/ActionGroup.tsx +++ b/packages/react-core/src/components/Form/ActionGroup.tsx @@ -1,7 +1,7 @@ import styles from '@patternfly/react-styles/css/components/Form/form'; import { css } from '@patternfly/react-styles'; -/** @deprecated Use ActionList, ActionListGroup, and ActionListItem instead. */ +/** @deprecated Use ActionList, ActionListGroup, and ActionListItem in a FormGroup instead. */ export interface ActionGroupProps extends React.HTMLProps { /** Anything that can be rendered as ActionGroup content. */ children?: React.ReactNode; @@ -9,7 +9,7 @@ export interface ActionGroupProps extends React.HTMLProps { className?: string; } -/** @deprecated Use ActionList, ActionListGroup, and ActionListItem instead. */ +/** @deprecated Use ActionList, ActionListGroup, and ActionListItem in a FormGroup instead. */ export const ActionGroup: React.FunctionComponent = ({ children = null, className = '', diff --git a/packages/react-core/src/components/Form/FormGroup.tsx b/packages/react-core/src/components/Form/FormGroup.tsx index abde71667e0..d20aa842a70 100644 --- a/packages/react-core/src/components/Form/FormGroup.tsx +++ b/packages/react-core/src/components/Form/FormGroup.tsx @@ -21,6 +21,8 @@ export interface FormGroupProps extends Omit, 'l isInline?: boolean; /** Sets the FormGroupControl to be stacked */ isStack?: boolean; + /** Sets the FormGroup action modifier. Used to contain form action buttons. */ + isAction?: boolean; /** Removes top spacer from label. */ hasNoPaddingTop?: boolean; /** ID of an individual field or a group of multiple fields. Required when a role of "group" or "radiogroup" is passed in. @@ -47,6 +49,7 @@ export const FormGroup: React.FunctionComponent = ({ isInline = false, hasNoPaddingTop = false, isStack = false, + isAction = false, fieldId, role, ouiaId, @@ -75,7 +78,7 @@ export const FormGroup: React.FunctionComponent = ({ return (
{ expect(screen.getByTestId('form-group-test-id').firstElementChild).toHaveClass('pf-m-no-padding-top'); }); + test('should render action form group variant', () => { + render( + + + + ); + expect(screen.getByTestId('form-group-test-id')).toHaveClass('pf-m-action'); + }); + test('should render form group variant with required label', () => { const { asFragment } = render( diff --git a/packages/react-core/src/components/Form/__tests__/__snapshots__/FormGroup.test.tsx.snap b/packages/react-core/src/components/Form/__tests__/__snapshots__/FormGroup.test.tsx.snap index 9c61b9cfb36..963cdc3e163 100644 --- a/packages/react-core/src/components/Form/__tests__/__snapshots__/FormGroup.test.tsx.snap +++ b/packages/react-core/src/components/Form/__tests__/__snapshots__/FormGroup.test.tsx.snap @@ -4,7 +4,7 @@ exports[`FormGroup should render correctly when label is not a string with Child
@@ -78,7 +78,7 @@ exports[`FormGroup should render form group variant with node label 1`] = `
@@ -114,7 +114,7 @@ exports[`FormGroup should render form group variant with required label 1`] = `
@@ -154,7 +154,7 @@ exports[`FormGroup should render form group variant without label 1`] = `
@@ -173,7 +173,7 @@ exports[`FormGroup should render form group with additional label info 1`] = `
@@ -218,14 +218,14 @@ exports[`FormGroup should render horizontal form group variant 1`] = `
@@ -260,14 +260,14 @@ exports[`FormGroup should render stacked horizontal form group variant 1`] = `
diff --git a/packages/react-core/src/components/Form/examples/FormBasic.tsx b/packages/react-core/src/components/Form/examples/FormBasic.tsx index e9317a2a2a8..a6f8b397923 100644 --- a/packages/react-core/src/components/Form/examples/FormBasic.tsx +++ b/packages/react-core/src/components/Form/examples/FormBasic.tsx @@ -125,16 +125,18 @@ export const FormBasic: React.FunctionComponent = () => { - - - - - - - - - - + + + + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/Form/examples/FormHorizontal.tsx b/packages/react-core/src/components/Form/examples/FormHorizontal.tsx index dfa3bc8f71c..4cb679880e1 100644 --- a/packages/react-core/src/components/Form/examples/FormHorizontal.tsx +++ b/packages/react-core/src/components/Form/examples/FormHorizontal.tsx @@ -114,16 +114,18 @@ export const FormHorizontal: React.FunctionComponent = () => { - - - - - - - - - - + + + + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx b/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx index a1bcd9f1e1a..0ba83999389 100644 --- a/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx +++ b/packages/react-core/src/components/Form/examples/FormLimitWidth.tsx @@ -125,16 +125,18 @@ export const FormLimitWidth: React.FunctionComponent = () => { - - - - - - - - - - + + + + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/Form/examples/FormState.tsx b/packages/react-core/src/components/Form/examples/FormState.tsx index 2245c980cfd..717809f540f 100644 --- a/packages/react-core/src/components/Form/examples/FormState.tsx +++ b/packages/react-core/src/components/Form/examples/FormState.tsx @@ -91,34 +91,36 @@ export const FormState = () => { - - - - - - - - - - + if (!values['input-id']) { + setError('input-id', 'Input value is required.'); + } else { + alert(`Form submitted with: \n ${JSON.stringify(values)}`); + } + }} + > + Submit + + + + + + + + {formStateExpanded && ( <> diff --git a/packages/react-core/src/components/LoginPage/LoginForm.tsx b/packages/react-core/src/components/LoginPage/LoginForm.tsx index e85350e7d4a..c6ce6ae3087 100644 --- a/packages/react-core/src/components/LoginPage/LoginForm.tsx +++ b/packages/react-core/src/components/LoginPage/LoginForm.tsx @@ -148,21 +148,23 @@ export const LoginForm: React.FunctionComponent = ({ /> )} - - - - - - - + + + + + + + + + ); }; diff --git a/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap b/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap index 90e5bb84227..cd9659d36ca 100644 --- a/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap +++ b/packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginForm.test.tsx.snap @@ -4,14 +4,14 @@ exports[`LoginForm LoginForm with rememberMeLabel 1`] = `
@@ -44,7 +44,7 @@ exports[`LoginForm LoginForm with rememberMeLabel 1`] = ` >
@@ -91,7 +91,7 @@ exports[`LoginForm LoginForm with rememberMeLabel 1`] = ` >
@@ -118,7 +118,7 @@ exports[`LoginForm LoginForm with rememberMeLabel 1`] = `
- + +
+
@@ -166,14 +177,14 @@ exports[`LoginForm LoginForm with show password 1`] = `
@@ -206,7 +217,7 @@ exports[`LoginForm LoginForm with show password 1`] = ` >
@@ -259,7 +270,7 @@ exports[`LoginForm LoginForm with show password 1`] = ` >
- + +
+
@@ -436,27 +458,38 @@ exports[`LoginForm should render Login form 1`] = `
- + +
+
diff --git a/packages/react-core/src/components/SearchInput/AdvancedSearchMenu.tsx b/packages/react-core/src/components/SearchInput/AdvancedSearchMenu.tsx index 047544a8635..67095d29d71 100644 --- a/packages/react-core/src/components/SearchInput/AdvancedSearchMenu.tsx +++ b/packages/react-core/src/components/SearchInput/AdvancedSearchMenu.tsx @@ -203,22 +203,24 @@ export const AdvancedSearchMenu: React.FunctionComponent {buildFormGroups()} {formAdditionalItems ? formAdditionalItems : null} - - - - - - {!!onClear && ( + + + - - )} - - + {!!onClear && ( + + + + )} + + + diff --git a/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap b/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap index c6e4c62e773..c8783dc12bc 100644 --- a/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap +++ b/packages/react-core/src/components/SearchInput/__tests__/__snapshots__/SearchInput.test.tsx.snap @@ -436,38 +436,46 @@ exports[`SearchInput advanced search with custom attributes 1`] = `
- -
-
- +
+
- Reset - - + +
+
diff --git a/packages/react-core/src/demos/Button/examples/ButtonProgress.tsx b/packages/react-core/src/demos/Button/examples/ButtonProgress.tsx index 7ee0f812d4e..01ca43e7173 100644 --- a/packages/react-core/src/demos/Button/examples/ButtonProgress.tsx +++ b/packages/react-core/src/demos/Button/examples/ButtonProgress.tsx @@ -35,32 +35,34 @@ export const ButtonProgress: React.FunctionComponent = () => { aria-label="password input" /> - - - - - - - + + + + + + + + + ); }; diff --git a/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx b/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx index 606aaa7f3f4..e547067c993 100644 --- a/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx +++ b/packages/react-core/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx @@ -292,22 +292,24 @@ export const SearchInputAdvancedComposable: React.FunctionComponent = () => { - - - - - - - {!!onClear && ( - - )} - - - + + + {!!onClear && ( + + )} + + + +