diff --git a/.changeset/rare-words-sin.md b/.changeset/rare-words-sin.md
new file mode 100644
index 00000000000..19fb5d70ecb
--- /dev/null
+++ b/.changeset/rare-words-sin.md
@@ -0,0 +1,6 @@
+---
+'@primer/react': minor
+---
+
+ActionList.Group + ActionList.TrailingAction: add missing className prop
+LabelGroup: add missing className prop
diff --git a/packages/react/src/ActionBar/ActionBar.test.tsx b/packages/react/src/ActionBar/ActionBar.test.tsx
index 44a0c25bcf6..135af92ef14 100644
--- a/packages/react/src/ActionBar/ActionBar.test.tsx
+++ b/packages/react/src/ActionBar/ActionBar.test.tsx
@@ -24,7 +24,7 @@ describe('ActionBar', () => {
behavesAsComponent({
Component: ActionBar,
- options: {skipAs: true, skipSx: true},
+ options: {skipAs: true, skipSx: true, skipClassName: true},
toRender: () => ,
})
diff --git a/packages/react/src/ActionList/ActionList.test.tsx b/packages/react/src/ActionList/ActionList.test.tsx
index c8d891dec20..7723425a724 100644
--- a/packages/react/src/ActionList/ActionList.test.tsx
+++ b/packages/react/src/ActionList/ActionList.test.tsx
@@ -34,6 +34,18 @@ describe('ActionList', () => {
toRender: () => ,
})
+ behavesAsComponent({
+ Component: ActionList.Divider,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => ,
+ })
+
+ behavesAsComponent({
+ Component: ActionList.TrailingAction,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => Action,
+ })
+
checkExports('ActionList', {
default: undefined,
ActionList,
@@ -144,4 +156,46 @@ describe('ActionList', () => {
)
expect(HTMLRender().container.querySelector('li[aria-hidden="true"]')).toHaveClass('test-class-name')
})
+
+ it('list and its sub-components support classname', () => {
+ const {container} = HTMLRender(
+
+
+ Heading
+
+
+ Item
+
+ Trailing Action
+
+
+
+
+ Link Item
+
+
+
+ Group Heading
+
+
+ Trailing Visual
+ Leading Visual
+ Description
+
+
+ ,
+ )
+
+ expect(container.querySelector('.list')).toBeInTheDocument()
+ expect(container.querySelector('.heading')).toBeInTheDocument()
+ expect(container.querySelector('.item')).toBeInTheDocument()
+ expect(container.querySelector('.trailing_action')).toBeInTheDocument()
+ expect(container.querySelector('.divider')).toBeInTheDocument()
+ expect(container.querySelector('.link')).toBeInTheDocument()
+ expect(container.querySelector('.group')).toBeInTheDocument()
+ expect(container.querySelector('.group_heading')).toBeInTheDocument()
+ expect(container.querySelector('.trailing')).toBeInTheDocument()
+ expect(container.querySelector('.leading')).toBeInTheDocument()
+ expect(container.querySelector('.description')).toBeInTheDocument()
+ })
})
diff --git a/packages/react/src/ActionList/Description.tsx b/packages/react/src/ActionList/Description.tsx
index 15b2e19c3f4..623f7c25ff3 100644
--- a/packages/react/src/ActionList/Description.tsx
+++ b/packages/react/src/ActionList/Description.tsx
@@ -130,3 +130,4 @@ export const Description: React.FC
)
}
+Description.displayName = 'ActionList.Description'
diff --git a/packages/react/src/ActionList/Divider.tsx b/packages/react/src/ActionList/Divider.tsx
index 5de6785ca75..e9897530406 100644
--- a/packages/react/src/ActionList/Divider.tsx
+++ b/packages/react/src/ActionList/Divider.tsx
@@ -52,3 +52,4 @@ export const Divider: React.FC>
/>
)
}
+Divider.displayName = 'ActionList.Divider'
diff --git a/packages/react/src/ActionList/Group.test.tsx b/packages/react/src/ActionList/Group.test.tsx
index 0c036d3df58..881aa5045bc 100644
--- a/packages/react/src/ActionList/Group.test.tsx
+++ b/packages/react/src/ActionList/Group.test.tsx
@@ -4,8 +4,21 @@ import theme from '../theme'
import {ActionList} from '.'
import {BaseStyles, ThemeProvider, ActionMenu} from '..'
import {FeatureFlags} from '../FeatureFlags'
+import {behavesAsComponent} from '../utils/testing'
describe('ActionList.Group', () => {
+ behavesAsComponent({
+ Component: ActionList.Group,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => ,
+ })
+
+ behavesAsComponent({
+ Component: ActionList.GroupHeading,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => ,
+ })
+
it('should throw an error when ActionList.GroupHeading has an `as` prop when it is used within ActionMenu context', async () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => jest.fn())
expect(() =>
diff --git a/packages/react/src/ActionList/Group.tsx b/packages/react/src/ActionList/Group.tsx
index 44be2fa68d4..52b61e4d36d 100644
--- a/packages/react/src/ActionList/Group.tsx
+++ b/packages/react/src/ActionList/Group.tsx
@@ -67,6 +67,10 @@ export type ActionListGroupProps = {
* The ARIA role describing the function of the list inside `Group` component. `listbox` or `menu` are a common values.
*/
role?: AriaRole
+ /**
+ * Custom class name to apply to the `Group`.
+ */
+ className?: string
} & SxProp & {
/**
* Whether multiple Items or a single Item can be selected in the Group. Overrides value on ActionList root.
@@ -86,6 +90,7 @@ export const Group: React.FC> = ({
auxiliaryText,
selectionVariant,
role,
+ className,
sx = defaultSxProp,
...props
}) => {
@@ -112,7 +117,13 @@ export const Group: React.FC> = ({
if (enabled) {
if (sx !== defaultSxProp) {
return (
-
+
{title && !slots.groupHeading ? (
// Escape hatch: supports old API in a non breaking way
@@ -135,7 +146,7 @@ export const Group: React.FC> = ({
)
}
return (
-
+
{title && !slots.groupHeading ? (
// Escape hatch: supports old API in a non breaking way
@@ -166,6 +177,7 @@ export const Group: React.FC> = ({
listStyle: 'none', // hide the ::marker inserted by browser's stylesheet
...sx,
}}
+ className={className}
{...props}
>
@@ -292,3 +304,6 @@ export const GroupHeading: React.FC
)
}
+
+GroupHeading.displayName = 'ActionList.GroupHeading'
+Group.displayName = 'ActionList.Group'
diff --git a/packages/react/src/ActionList/Heading.test.tsx b/packages/react/src/ActionList/Heading.test.tsx
index aff9a56923a..e87cd4133de 100644
--- a/packages/react/src/ActionList/Heading.test.tsx
+++ b/packages/react/src/ActionList/Heading.test.tsx
@@ -4,8 +4,15 @@ import theme from '../theme'
import {ActionList} from '.'
import {BaseStyles, ThemeProvider, ActionMenu} from '..'
import {FeatureFlags} from '../FeatureFlags'
+import {behavesAsComponent} from '../utils/testing'
describe('ActionList.Heading', () => {
+ behavesAsComponent({
+ Component: ActionList.Heading,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => ,
+ })
+
it('should render the ActionList.Heading component as a heading with the given heading level', async () => {
const container = HTMLRender(
diff --git a/packages/react/src/ActionList/Item.test.tsx b/packages/react/src/ActionList/Item.test.tsx
index 5751126aa93..0570f62cd61 100644
--- a/packages/react/src/ActionList/Item.test.tsx
+++ b/packages/react/src/ActionList/Item.test.tsx
@@ -4,6 +4,7 @@ import React from 'react'
import {ActionList} from '.'
import {BookIcon} from '@primer/octicons-react'
import {FeatureFlags} from '../FeatureFlags'
+import {behavesAsComponent} from '../utils/testing'
function SimpleActionList(): JSX.Element {
return (
@@ -57,6 +58,48 @@ function SingleSelectListStory(): JSX.Element {
}
describe('ActionList.Item', () => {
+ behavesAsComponent({
+ Component: ActionList.Item,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => ,
+ })
+
+ behavesAsComponent({
+ Component: ActionList.LinkItem,
+ options: {skipAs: true, skipSx: true},
+ toRender: () => ,
+ })
+
+ behavesAsComponent({
+ Component: ActionList.TrailingVisual,
+ options: {skipAs: true, skipSx: true, skipClassName: true},
+ toRender: () => (
+
+ Trailing Visual
+
+ ),
+ })
+
+ behavesAsComponent({
+ Component: ActionList.LeadingVisual,
+ options: {skipAs: true, skipSx: true, skipClassName: true},
+ toRender: () => (
+
+ Leading Visual
+
+ ),
+ })
+
+ behavesAsComponent({
+ Component: ActionList.Description,
+ options: {skipAs: true, skipSx: true, skipClassName: true},
+ toRender: () => (
+
+ Description
+
+ ),
+ })
+
it('should have aria-keyshortcuts applied to the correct element', async () => {
const {container} = HTMLRender()
const linkOptions = await waitFor(() => container.querySelectorAll('a'))
diff --git a/packages/react/src/ActionList/LinkItem.tsx b/packages/react/src/ActionList/LinkItem.tsx
index fd9d908f292..d495e9c7b3f 100644
--- a/packages/react/src/ActionList/LinkItem.tsx
+++ b/packages/react/src/ActionList/LinkItem.tsx
@@ -137,3 +137,5 @@ export const LinkItem = React.forwardRef(
)
},
) as PolymorphicForwardRefComponent<'a', ActionListLinkItemProps>
+
+LinkItem.displayName = 'ActionList.LinkItem'
diff --git a/packages/react/src/ActionList/TrailingAction.tsx b/packages/react/src/ActionList/TrailingAction.tsx
index 70c931efb03..efaee69bdec 100644
--- a/packages/react/src/ActionList/TrailingAction.tsx
+++ b/packages/react/src/ActionList/TrailingAction.tsx
@@ -67,6 +67,7 @@ export const TrailingAction = forwardRef(
sx={{
flexShrink: 0,
}}
+ className={className}
>
{icon ? (
)
}
+
+LeadingVisual.displayName = 'ActionList.LeadingVisual'
+TrailingVisual.displayName = 'ActionList.TrailingVisual'
diff --git a/packages/react/src/ConfirmationDialog/ConfirmationDialog.test.tsx b/packages/react/src/ConfirmationDialog/ConfirmationDialog.test.tsx
index bd9de14a80b..2aad3a23dda 100644
--- a/packages/react/src/ConfirmationDialog/ConfirmationDialog.test.tsx
+++ b/packages/react/src/ConfirmationDialog/ConfirmationDialog.test.tsx
@@ -73,7 +73,7 @@ describe('ConfirmationDialog', () => {
behavesAsComponent({
Component: ConfirmationDialog,
toRender: () => ,
- options: {skipAs: true, skipSx: true},
+ options: {skipAs: true, skipSx: true, skipClassName: true},
})
checkExports('ConfirmationDialog/ConfirmationDialog', {
diff --git a/packages/react/src/Dialog/Dialog.test.tsx b/packages/react/src/Dialog/Dialog.test.tsx
index 39e9dd71704..9195ca85c53 100644
--- a/packages/react/src/Dialog/Dialog.test.tsx
+++ b/packages/react/src/Dialog/Dialog.test.tsx
@@ -21,7 +21,7 @@ describe('Dialog', () => {
behavesAsComponent({
Component: Dialog,
- options: {skipAs: true, skipSx: true},
+ options: {skipAs: true, skipSx: true, skipClassName: true},
toRender: () => (