Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e13d2ee

Browse filesBrowse files
committed
refactor(CAccordion): improve accessibility
1 parent adbc513 commit e13d2ee
Copy full SHA for e13d2ee

File tree

6 files changed

+21
-219
lines changed
Filter options

6 files changed

+21
-219
lines changed

‎packages/coreui-react/src/components/accordion/CAccordion.tsx

Copy file name to clipboardExpand all lines: packages/coreui-react/src/components/accordion/CAccordion.tsx
+6-71Lines changed: 6 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,25 @@ import React, { createContext, forwardRef, HTMLAttributes, useState } from 'reac
22
import PropTypes from 'prop-types'
33
import classNames from 'classnames'
44

5-
import { mergeClassNames } from '../../utils'
6-
75
export interface CAccordionProps extends HTMLAttributes<HTMLDivElement> {
86
/**
9-
* Determines which accordion item is currently active (expanded) by default.
10-
* Accepts a number or string corresponding to the `itemKey` of the desired accordion item.
11-
*
12-
* @example
13-
* <CAccordion activeItemKey="1">...</CAccordion>
7+
* The active item key.
148
*/
159
activeItemKey?: number | string
16-
1710
/**
18-
* When set to `true`, multiple accordion items within the React Accordion can be open simultaneously.
19-
* This is ideal for scenarios where users need to view multiple sections at once without collapsing others.
20-
*
21-
* @default false
22-
*
23-
* @example
24-
* <CAccordion alwaysOpen>...</CAccordion>
11+
* Make accordion items stay open when another item is opened
2512
*/
2613
alwaysOpen?: boolean
27-
2814
/**
29-
* Allows you to apply custom CSS classes to the React Accordion for enhanced styling and theming.
30-
*
31-
* @example
32-
* <CAccordion className="my-custom-accordion">...</CAccordion>
15+
* A string of all className you want applied to the base component.
3316
*/
3417
className?: string
35-
3618
/**
37-
* Allows overriding or extending the default CSS class names used in the component.
38-
*
39-
* - `ACCORDION`: Base class for the accordion component.
40-
* - `ACCORDION_FLUSH`: Class applied when the `flush` prop is set to true, ensuring an edge-to-edge layout.
41-
*
42-
* Use this prop to customize the styles of specific parts of the accordion.
43-
*
44-
* @example
45-
* const customClasses = {
46-
* ACCORDION: 'custom-accordion',
47-
* ACCORDION_FLUSH: 'custom-accordion-flush'
48-
* }
49-
* <CAccordion customClassNames={customClasses}>...</CAccordion>
50-
*/
51-
customClassNames?: Partial<typeof ACCORDION_CLASS_NAMES>
52-
53-
/**
54-
* When `flush` is set to `true`, the React Accordion renders edge-to-edge with its parent container,
55-
* creating a seamless and modern look ideal for minimalist designs.
56-
*
57-
* @default false
58-
*
59-
* @example
60-
* <CAccordion flush>...</CAccordion>
19+
* Removes the default background-color, some borders, and some rounded corners to render accordions edge-to-edge with their parent container.
6120
*/
6221
flush?: boolean
6322
}
6423

65-
export const ACCORDION_CLASS_NAMES = {
66-
/**
67-
* Base class for the accordion container.
68-
*/
69-
ACCORDION: 'accordion',
70-
71-
/**
72-
* Applied when the `flush` prop is enabled.
73-
*/
74-
ACCORDION_FLUSH: 'accordion-flush',
75-
}
76-
7724
export interface CAccordionContextProps {
7825
_activeItemKey?: number | string
7926
alwaysOpen?: boolean
@@ -83,24 +30,12 @@ export interface CAccordionContextProps {
8330
export const CAccordionContext = createContext({} as CAccordionContextProps)
8431

8532
export const CAccordion = forwardRef<HTMLDivElement, CAccordionProps>(
86-
(
87-
{ children, activeItemKey, alwaysOpen = false, className, customClassNames, flush, ...rest },
88-
ref,
89-
) => {
33+
({ children, activeItemKey, alwaysOpen = false, className, flush, ...rest }, ref) => {
9034
const [_activeItemKey, setActiveKey] = useState(activeItemKey)
9135

92-
const mergedClassNames = mergeClassNames<typeof ACCORDION_CLASS_NAMES>(
93-
ACCORDION_CLASS_NAMES,
94-
customClassNames,
95-
)
96-
9736
return (
9837
<div
99-
className={classNames(
100-
mergedClassNames.ACCORDION,
101-
{ [mergedClassNames.ACCORDION_FLUSH]: flush },
102-
className,
103-
)}
38+
className={classNames('accordion', { 'accordion-flush': flush }, className)}
10439
{...rest}
10540
ref={ref}
10641
>

‎packages/coreui-react/src/components/accordion/CAccordionBody.tsx

Copy file name to clipboardExpand all lines: packages/coreui-react/src/components/accordion/CAccordionBody.tsx
+5-44Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,60 +5,21 @@ import classNames from 'classnames'
55
import { CAccordionItemContext } from './CAccordionItem'
66

77
import { CCollapse } from './../collapse/CCollapse'
8-
import { mergeClassNames } from '../../utils'
98

109
export interface CAccordionBodyProps extends HTMLAttributes<HTMLDivElement> {
1110
/**
12-
* Allows you to apply custom CSS classes to the React Accordion Body for enhanced styling and theming.
13-
*
14-
* @example
15-
* <CAccordionBody className="custom-accordion-body">...</CAccordionBody>
11+
* A string of all className you want applied to the base component.
1612
*/
1713
className?: string
18-
19-
/**
20-
* Allows overriding or extending the default CSS class names used in the accordion body component.
21-
* Accepts a partial object matching the shape of `ACCORDION_BODY_CLASS_NAMES`, which includes:
22-
*
23-
* - `ACCORDION_COLLAPSE`: Base class for the collapse container in the accordion body.
24-
* - `ACCORDION_BODY`: Base class for the main content container inside the accordion body.
25-
*
26-
* Use this prop to customize the styles of specific parts of the accordion body.
27-
*
28-
* @example
29-
* const customClasses = {
30-
* ACCORDION_COLLAPSE: 'custom-collapse-class',
31-
* ACCORDION_BODY: 'custom-body-class',
32-
* }
33-
* <CAccordionBody customClassNames={customClasses}>...</CAccordionBody>
34-
*/
35-
customClassNames?: Partial<typeof ACCORDION_BODY_CLASS_NAMES>
36-
}
37-
38-
export const ACCORDION_BODY_CLASS_NAMES = {
39-
/**
40-
* Used for managing collapsible behavior in the accordion body.
41-
*/
42-
ACCORDION_COLLAPSE: 'accordion-collapse',
43-
44-
/**
45-
* Styles the main content container inside the accordion.
46-
*/
47-
ACCORDION_BODY: 'accordion-body',
4814
}
4915

5016
export const CAccordionBody = forwardRef<HTMLDivElement, CAccordionBodyProps>(
51-
({ children, className, customClassNames, ...rest }, ref) => {
52-
const { id, visible } = useContext(CAccordionItemContext)
53-
54-
const mergedClassNames = mergeClassNames<typeof ACCORDION_BODY_CLASS_NAMES>(
55-
ACCORDION_BODY_CLASS_NAMES,
56-
customClassNames,
57-
)
17+
({ children, className, ...rest }, ref) => {
18+
const { visible } = useContext(CAccordionItemContext)
5819

5920
return (
60-
<CCollapse id={id} className={mergedClassNames.ACCORDION_COLLAPSE} visible={visible}>
61-
<div className={classNames(mergedClassNames.ACCORDION_BODY, className)} {...rest} ref={ref}>
21+
<CCollapse className="accordion-collapse" visible={visible}>
22+
<div className={classNames('accordion-body', className)} {...rest} ref={ref}>
6223
{children}
6324
</div>
6425
</CCollapse>

‎packages/coreui-react/src/components/accordion/CAccordionButton.tsx

Copy file name to clipboardExpand all lines: packages/coreui-react/src/components/accordion/CAccordionButton.tsx
+3-31Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,21 @@ import classNames from 'classnames'
44

55
import { CAccordionItemContext } from './CAccordionItem'
66

7-
import { mergeClassNames } from '../../utils'
8-
97
export interface CAccordionButtonProps extends HTMLAttributes<HTMLButtonElement> {
108
/**
11-
* Styles the clickable element in the accordion header.
9+
* A string of all className you want applied to the base component.
1210
*/
1311
className?: string
14-
15-
/**
16-
* Allows overriding or extending the default CSS class names used in the accordion button component.
17-
* Accepts a partial object matching the shape of `CLASS_NAMES`, which includes:
18-
*
19-
* - `ACCORDION_BUTTON`: Base class for the accordion button.
20-
*
21-
* Use this prop to customize the styles of the accordion button.
22-
*
23-
* @example
24-
* const customClasses = {
25-
* ACCORDION_BUTTON: 'custom-button-class',
26-
* }
27-
* <CAccordionButton customClassNames={customClasses}>...</CAccordionButton>
28-
*/
29-
customClassNames?: Partial<typeof CLASS_NAMES>
30-
}
31-
32-
export const CLASS_NAMES = {
33-
ACCORDION_BUTTON: 'accordion-button',
3412
}
3513

3614
export const CAccordionButton = forwardRef<HTMLButtonElement, CAccordionButtonProps>(
37-
({ children, className, customClassNames, ...rest }, ref) => {
15+
({ children, className, ...rest }, ref) => {
3816
const { id, visible, setVisible } = useContext(CAccordionItemContext)
3917

40-
const mergedClassNames = mergeClassNames<typeof CLASS_NAMES>(CLASS_NAMES, customClassNames)
41-
4218
return (
4319
<button
4420
type="button"
45-
className={classNames(
46-
mergedClassNames.ACCORDION_BUTTON,
47-
{ collapsed: !visible },
48-
className,
49-
)}
21+
className={classNames('accordion-button', { collapsed: !visible }, className)}
5022
aria-controls={id}
5123
aria-expanded={visible}
5224
onClick={() => setVisible(!visible)}

‎packages/coreui-react/src/components/accordion/CAccordionHeader.tsx

Copy file name to clipboardExpand all lines: packages/coreui-react/src/components/accordion/CAccordionHeader.tsx
+3-39Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,19 @@ import PropTypes from 'prop-types'
33
import classNames from 'classnames'
44

55
import { CAccordionButton } from './CAccordionButton'
6-
import { mergeClassNames } from '../../utils'
76

87
export interface CAccordionHeaderProps extends HTMLAttributes<HTMLDivElement> {
98
/**
109
* A string of all className you want applied to the base component.
1110
*/
1211
className?: string
13-
/**
14-
* Allows overriding or extending the default CSS class names used in the accordion header component.
15-
* Accepts a partial object matching the shape of `ACCORDION_HEADER_CLASS_NAMES`, which includes:
16-
*
17-
* - `ACCORDION_HEADER`: Base class for the accordion header container.
18-
* - `ACCORDION_BUTTON`: Class applied to the button within the accordion header.
19-
*
20-
* Use this prop to customize the styles of specific parts of the accordion header.
21-
*
22-
* @example
23-
* const customClasses = {
24-
* ACCORDION_HEADER: 'custom-header-class',
25-
* ACCORDION_BUTTON: 'custom-button-class',
26-
* }
27-
* <CAccordionHeader customClassNames={customClasses}>...</CAccordionHeader>
28-
*/
29-
customClassNames?: Partial<typeof ACCORDION_HEADER_CLASS_NAMES>
30-
}
31-
32-
export const ACCORDION_HEADER_CLASS_NAMES = {
33-
/**
34-
* Styles the header container of an accordion item.
35-
*/
36-
ACCORDION_HEADER: 'accordion-header',
37-
38-
/**
39-
* Styles the clickable element in the accordion header.
40-
*/
41-
ACCORDION_BUTTON: 'accordion-button',
4212
}
4313

4414
export const CAccordionHeader = forwardRef<HTMLDivElement, CAccordionHeaderProps>(
45-
({ children, className, customClassNames, ...rest }, ref) => {
46-
const mergedClassNames = mergeClassNames<typeof ACCORDION_HEADER_CLASS_NAMES>(
47-
ACCORDION_HEADER_CLASS_NAMES,
48-
customClassNames,
49-
)
15+
({ children, className, ...rest }, ref) => {
5016
return (
51-
<div className={classNames(mergedClassNames.ACCORDION_HEADER, className)} {...rest} ref={ref}>
52-
<CAccordionButton className={mergedClassNames.ACCORDION_HEADER}>
53-
{children}
54-
</CAccordionButton>
17+
<div className={classNames('accordion-header', className)} {...rest} ref={ref}>
18+
<CAccordionButton>{children}</CAccordionButton>
5519
</div>
5620
)
5721
},

‎packages/coreui-react/src/components/accordion/CAccordionItem.tsx

Copy file name to clipboardExpand all lines: packages/coreui-react/src/components/accordion/CAccordionItem.tsx
+3-33Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import PropTypes from 'prop-types'
1212
import classNames from 'classnames'
1313

1414
import { CAccordionContext } from './CAccordion'
15-
import { mergeClassNames } from '../../utils'
1615

1716
export interface CAccordionItemContextProps {
1817
id: string
@@ -27,49 +26,20 @@ export interface CAccordionItemProps extends HTMLAttributes<HTMLDivElement> {
2726
* A string of all className you want applied to the base component.
2827
*/
2928
className?: string
30-
31-
/**
32-
* Allows overriding or extending the default CSS class names used in the accordion item component.
33-
* Accepts a partial object matching the shape of `ACCORDION_ITEM_CLASS_NAMES`, which includes:
34-
*
35-
* - `ACCORDION_ITEM`: Base class for an individual accordion item.
36-
*
37-
* Use this prop to customize the styles of specific parts of the accordion item.
38-
*
39-
* @example
40-
* const customClasses = {
41-
* ACCORDION_ITEM: 'custom-item-class',
42-
* }
43-
* <CAccordionItem customClassNames={customClasses}>...</CAccordionItem>
44-
*/
45-
customClassNames?: Partial<typeof ACCORDION_ITEM_CLASS_NAMES>
46-
4729
/**
4830
* Item key.
4931
*/
5032
itemKey?: number | string
5133
}
5234

53-
export const ACCORDION_ITEM_CLASS_NAMES = {
54-
/**
55-
* Base class for an individual accordion item.
56-
*/
57-
ACCORDION_ITEM: 'accordion-item',
58-
}
59-
6035
export const CAccordionItem = forwardRef<HTMLDivElement, CAccordionItemProps>(
61-
({ children, className, customClassNames, itemKey, ...rest }, ref) => {
36+
({ children, className, itemKey, ...rest }, ref) => {
6237
const id = useId()
63-
const _itemKey = useRef(itemKey ?? Math.random().toString(36).slice(2, 11))
38+
const _itemKey = useRef(itemKey ?? id)
6439

6540
const { _activeItemKey, alwaysOpen, setActiveKey } = useContext(CAccordionContext)
6641
const [visible, setVisible] = useState(Boolean(_activeItemKey === _itemKey.current))
6742

68-
const mergedClassNames = mergeClassNames<typeof ACCORDION_ITEM_CLASS_NAMES>(
69-
ACCORDION_ITEM_CLASS_NAMES,
70-
customClassNames,
71-
)
72-
7343
useEffect(() => {
7444
if (!alwaysOpen && visible) {
7545
setActiveKey(_itemKey.current)
@@ -81,7 +51,7 @@ export const CAccordionItem = forwardRef<HTMLDivElement, CAccordionItemProps>(
8151
}, [_activeItemKey])
8252

8353
return (
84-
<div className={classNames(mergedClassNames.ACCORDION_ITEM, className)} {...rest} ref={ref}>
54+
<div className={classNames('accordion-item', className)} {...rest} ref={ref}>
8555
<CAccordionItemContext.Provider value={{ id, setVisible, visible }}>
8656
{children}
8757
</CAccordionItemContext.Provider>

‎packages/docs/content/components/accordion/examples/AccordionExample.tsx

Copy file name to clipboardExpand all lines: packages/docs/content/components/accordion/examples/AccordionExample.tsx
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const AccordionExample = () => {
55
return (
66
<CAccordion activeItemKey={2}>
77
<CAccordionItem itemKey={1}>
8-
<CAccordionHeader>Accordion Item #1 TSX</CAccordionHeader>
8+
<CAccordionHeader>Accordion Item #1</CAccordionHeader>
99
<CAccordionBody>
1010
<strong>This is the first item&#39;s accordion body.</strong> It is hidden by default,
1111
until the collapse plugin adds the appropriate classes that we use to style each element.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.