diff --git a/.changeset/heavy-hairs-join.md b/.changeset/heavy-hairs-join.md new file mode 100644 index 0000000000..a706ffe55a --- /dev/null +++ b/.changeset/heavy-hairs-join.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/accordion": patch +--- + +Make the accordion item heading tag customizable to satisfy a11y needs. Headings on web pages need to be consistent and semantic; this will help all users better find the content they are looking for. (#2950) diff --git a/apps/docs/content/docs/components/accordion.mdx b/apps/docs/content/docs/components/accordion.mdx index 0b95f6e804..587162d03c 100644 --- a/apps/docs/content/docs/components/accordion.mdx +++ b/apps/docs/content/docs/components/accordion.mdx @@ -220,21 +220,22 @@ Here's an example of how to customize the accordion styles: ### Accordion Item Props -| Attribute | Type | Description | Default | -| ------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------- | -| children | `ReactNode` \| `string` | The content of the component. | | -| title | `ReactNode` \| `string` | The accordion item title. | | -| subtitle | `ReactNode` \| `string` | The accordion item subtitle. | | -| indicator | [IndicatorProps](#accordion-item-indicator-props) | The accordion item `expanded` indicator, usually an arrow icon. | | -| startContent | `ReactNode` | The accordion item start content, usually an icon or avatar. | | -| motionProps | [MotionProps](#motion-props) | The props to modify the framer motion animation. Use the `variants` API to create your own animation. | | -| isCompact | `boolean` | Whether the AccordionItem is compact. | `false` | -| isDisabled | `boolean` | The current disabled status. | `false` | -| keepContentMounted | `boolean` | Whether the AccordionItem content is kept mounted when closed. | `false` | -| hideIndicator | `boolean` | Whether the AccordionItem indicator is hidden. | `false` | -| disableAnimation | `boolean` | Whether the AccordionItem animation is disabled. | `false` | -| disableIndicatorAnimation | `boolean` | Whether the AccordionItem indicator animation is disabled. | `false` | -| classNames | [Classnames](#accordion-item-classnames) | Allows to set custom class names for the accordion item slots. | - | +| Attribute | Type | Description | Default | +|---------------------------|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|---------| +| children | `ReactNode` \| `string` | The content of the component. | | +| title | `ReactNode` \| `string` | The accordion item title. | | +| subtitle | `ReactNode` \| `string` | The accordion item subtitle. | | +| indicator | [IndicatorProps](#accordion-item-indicator-props) | The accordion item `expanded` indicator, usually an arrow icon. | | +| startContent | `ReactNode` | The accordion item start content, usually an icon or avatar. | | +| motionProps | [MotionProps](#motion-props) | The props to modify the framer motion animation. Use the `variants` API to create your own animation. | | +| isCompact | `boolean` | Whether the AccordionItem is compact. | `false` | +| isDisabled | `boolean` | The current disabled status. | `false` | +| keepContentMounted | `boolean` | Whether the AccordionItem content is kept mounted when closed. | `false` | +| hideIndicator | `boolean` | Whether the AccordionItem indicator is hidden. | `false` | +| disableAnimation | `boolean` | Whether the AccordionItem animation is disabled. | `false` | +| disableIndicatorAnimation | `boolean` | Whether the AccordionItem indicator animation is disabled. | `false` | +| HeadingComponent | `React.ElementType` | Customizable heading tag for Web accessibility. Use headings to describe content and use them consistently and semantically. | `h2` | +| classNames | [Classnames](#accordion-item-classnames) | Allows to set custom class names for the accordion item slots. | - | ### Accordion Item Events diff --git a/packages/components/accordion/src/accordion-item.tsx b/packages/components/accordion/src/accordion-item.tsx index 21fb94a93d..580c0a1601 100644 --- a/packages/components/accordion/src/accordion-item.tsx +++ b/packages/components/accordion/src/accordion-item.tsx @@ -11,6 +11,7 @@ export interface AccordionItemProps extends UseAccordionItemProps {} const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => { const { Component, + HeadingComponent, classNames, slots, indicator, @@ -89,7 +90,7 @@ const AccordionItem = forwardRef<"button", AccordionItemProps>((props, ref) => { return ( -

+ -

+ {content}
); diff --git a/packages/components/accordion/src/base/accordion-item-base.tsx b/packages/components/accordion/src/base/accordion-item-base.tsx index 7c61e30002..d97226fb38 100644 --- a/packages/components/accordion/src/base/accordion-item-base.tsx +++ b/packages/components/accordion/src/base/accordion-item-base.tsx @@ -4,6 +4,7 @@ import type { SlotsToClasses, } from "@nextui-org/theme"; +import {As} from "@nextui-org/system"; import {ItemProps, BaseItem} from "@nextui-org/aria-utils"; import {FocusableProps, PressEvents} from "@react-types/shared"; import {ReactNode, MouseEventHandler} from "react"; @@ -85,6 +86,12 @@ export interface Props * ``` */ classNames?: SlotsToClasses; + /** + * Customizable heading tag for Web accessibility: + * use headings to describe content and use them consistently and semantically. + * This will help all users to better find the content they are looking for. + */ + HeadingComponent?: As; } export type AccordionItemBaseProps = Props & AccordionItemVariantProps; diff --git a/packages/components/accordion/src/use-accordion-item.ts b/packages/components/accordion/src/use-accordion-item.ts index ec4f85ef09..ab947cff43 100644 --- a/packages/components/accordion/src/use-accordion-item.ts +++ b/packages/components/accordion/src/use-accordion-item.ts @@ -58,6 +58,7 @@ export function useAccordionItem(props: UseAccordionItemP disableAnimation = false, keepContentMounted = false, disableIndicatorAnimation = false, + HeadingComponent = as || "h2", onPress, onPressStart, onPressEnd, @@ -237,6 +238,7 @@ export function useAccordionItem(props: UseAccordionItemP return { Component, + HeadingComponent, item, slots, classNames,