diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 00000000..74d8bc85
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,11 @@
+{
+ "permissions": {
+ "allow": [
+ "mcp__ide__getDiagnostics",
+ "Bash(npm run lint:*)",
+ "Bash(npm test:*)"
+ ],
+ "deny": [],
+ "ask": []
+ }
+}
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 00000000..33a8fd20
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,135 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Overview
+
+CoreUI for React is a comprehensive React.js components library built on top of Bootstrap 5 and TypeScript. It's organized as a monorepo using Lerna with multiple packages including the main React component library, icons, charts, and documentation.
+
+## Repository Structure
+
+This is a **Lerna monorepo** with the following key packages:
+- `packages/coreui-react/` - Main React components library (TypeScript)
+- `packages/coreui-icons-react/` - Icon components for React
+- `packages/coreui-react-chartjs/` - Chart.js integration for React
+- `packages/docs/` - Gatsby-based documentation site
+
+## Development Commands
+
+### Root Level Commands
+- `npm run lint` - Lint all packages
+- `npm run test` - Run tests for all packages
+- `npm run test:update` - Update snapshots for all packages
+
+### Package-Specific Commands (using Lerna)
+- `npm run lib:build` - Build main React library
+- `npm run lib:test` - Test main React library only
+- `npm run lib:test:update` - Update main library test snapshots
+- `npm run icons:build` - Build icons package
+- `npm run charts:build` - Build charts package
+- `npm run docs:dev` - Start documentation dev server
+- `npm run docs:build` - Build documentation
+
+### Working with Individual Packages
+Navigate to specific packages to run commands directly:
+```bash
+cd packages/coreui-react
+npm test -- src/components/focus-trap/__tests__/CFocusTrap.spec.tsx # Run specific test
+npm run build # Build this package only
+```
+
+### Running Single Tests
+To run a specific test file:
+```bash
+cd packages/coreui-react
+npm test -- path/to/test.spec.tsx
+```
+
+## Architecture
+
+### Component Organization
+Each component follows a consistent structure:
+```
+components/[component-name]/
+├── C[ComponentName].tsx # Main component
+├── C[ComponentName]Part.tsx # Sub-components
+├── index.ts # Exports
+├── types.ts # TypeScript types (if complex)
+├── utils.ts # Utility functions (if any)
+├── const.ts # Constants (if any)
+└── __tests__/ # Tests and snapshots
+ ├── C[ComponentName].spec.tsx
+ └── __snapshots__/
+```
+
+### Component Development Patterns
+
+**Props Interface**: All components have well-documented TypeScript interfaces with JSDoc comments focusing on accessibility and SEO benefits.
+
+**Ref Forwarding**: Components forward refs properly to DOM elements for accessibility and integration.
+
+**Testing**: Uses React Testing Library with Jest, focusing on behavior over implementation details. Each component has snapshot tests and behavioral tests.
+
+**Styling**: Components use Bootstrap 5 classes and are compatible with `@coreui/coreui` CSS library.
+
+### Key Development Principles
+
+**TypeScript First**: All components are written in TypeScript with proper type definitions.
+
+**Accessibility Focus**: Components implement WCAG 2.1 standards and include proper ARIA attributes.
+
+**Bootstrap Compatible**: Components extend Bootstrap 5 functionality while maintaining compatibility.
+
+**No Extra DOM**: Many components avoid adding wrapper elements, using ref merging instead (see `focus-trap` component).
+
+**Utility Separation**: Complex components separate utilities into dedicated files (`utils.ts`, `const.ts`).
+
+## Testing
+
+### Test Structure
+- Snapshot tests for UI consistency
+- Behavioral tests for user interactions
+- Accessibility tests for focus management
+- Props validation tests
+
+### Test Environment
+- Jest with JSDOM environment
+- React Testing Library for component testing
+- `@testing-library/jest-dom` for DOM assertions
+
+### Running Tests
+Tests are run at the package level. Some complex focus management tests may not work perfectly in JSDOM but will work in real browsers.
+
+## Build System
+
+### Rollup Configuration
+Each package uses Rollup for building:
+- ESM and CommonJS outputs
+- TypeScript compilation
+- Separate bundles for different environments
+
+### Package Dependencies
+- `@coreui/coreui` - Core CSS library
+- `@popperjs/core` - For positioning (tooltips, dropdowns)
+- `prop-types` - Runtime type checking
+- React 17+ peer dependency
+
+## Component Development
+
+### Creating New Components
+1. Follow the directory structure pattern
+2. Use TypeScript interfaces with comprehensive JSDoc
+3. Implement proper ref forwarding
+4. Add comprehensive tests (snapshot + behavioral)
+5. Export from package index files
+6. Consider accessibility from the start
+
+### Refactoring Components
+When refactoring complex components:
+1. Separate utilities into `utils.ts` and constants into `const.ts`
+2. Maintain backward compatibility with existing props
+3. Update tests to match new structure
+4. Keep the same export interface
+
+### Focus Management
+For components requiring focus management (modals, dropdowns), use the patterns established in the `focus-trap` component, which implements proper Tab/Shift+Tab cycling and external focus redirection.
\ No newline at end of file
diff --git a/README.md b/README.md
index c0e48a57..edd87fba 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@
·
Request feature
·
- Roadmap
+ Roadmap
·
Blog
@@ -48,7 +48,7 @@
Several quick start options are available:
-- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.8.0.zip)
+- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.9.0.zip)
- Clone the repo: `git clone https://github.com/coreui/coreui-react.git`
- Install with [npm](https://www.npmjs.com/): `npm install @coreui/react`
- Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/react`
diff --git a/lerna.json b/lerna.json
index 8a0e6ac0..0a49658b 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,6 +1,6 @@
{
"npmClient": "yarn",
"packages": ["packages/*"],
- "version": "5.8.0",
+ "version": "5.9.0",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
diff --git a/package.json b/package.json
index 58169718..cdacc619 100644
--- a/package.json
+++ b/package.json
@@ -22,18 +22,18 @@
"test:update": "npm-run-all charts:test:update icons:test:update lib:test:update"
},
"devDependencies": {
- "@typescript-eslint/parser": "^8.42.0",
- "eslint": "^9.34.0",
+ "@typescript-eslint/parser": "^8.44.0",
+ "eslint": "^9.35.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
- "eslint-plugin-unicorn": "^60.0.0",
- "globals": "^16.3.0",
- "lerna": "^8.2.3",
+ "eslint-plugin-unicorn": "^61.0.2",
+ "globals": "^16.4.0",
+ "lerna": "^8.2.4",
"npm-run-all": "^4.1.5",
"prettier": "^3.6.2",
- "typescript-eslint": "^8.42.0"
+ "typescript-eslint": "^8.44.0"
},
"overrides": {
"gatsby-remark-external-links": {
diff --git a/packages/coreui-react/README.md b/packages/coreui-react/README.md
index 269cb3cd..ddfb584b 100644
--- a/packages/coreui-react/README.md
+++ b/packages/coreui-react/README.md
@@ -46,7 +46,7 @@
Several quick start options are available:
-- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.8.0.zip)
+- [Download the latest release](https://github.com/coreui/coreui-react/archive/v5.9.0.zip)
- Clone the repo: `git clone https://github.com/coreui/coreui-react.git`
- Install with [npm](https://www.npmjs.com/): `npm install @coreui/react`
- Install with [yarn](https://yarnpkg.com/): `yarn add @coreui/react`
diff --git a/packages/coreui-react/package.json b/packages/coreui-react/package.json
index 99d28f01..c1e7c2cc 100644
--- a/packages/coreui-react/package.json
+++ b/packages/coreui-react/package.json
@@ -1,6 +1,6 @@
{
"name": "@coreui/react",
- "version": "5.8.0",
+ "version": "5.9.0",
"description": "UI Components Library for React.js",
"keywords": [
"react",
@@ -53,8 +53,8 @@
"@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0",
"@types/jest": "^29.5.14",
- "@types/prop-types": "15.8.05",
- "@types/react": "^19.1.12",
+ "@types/prop-types": "15.7.15",
+ "@types/react": "^19.1.13",
"@types/react-dom": "^19.1.9",
"@types/react-transition-group": "^4.4.12",
"classnames": "^2.5.1",
@@ -64,8 +64,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-transition-group": "^4.4.5",
- "rollup": "^4.50.0",
- "ts-jest": "^29.4.1",
+ "rollup": "^4.50.2",
+ "ts-jest": "^29.4.2",
"tslib": "^2.8.1",
"typescript": "^5.9.2"
},
diff --git a/packages/coreui-react/src/components/dropdown/CDropdown.tsx b/packages/coreui-react/src/components/dropdown/CDropdown.tsx
index e32efa65..3c47a20b 100644
--- a/packages/coreui-react/src/components/dropdown/CDropdown.tsx
+++ b/packages/coreui-react/src/components/dropdown/CDropdown.tsx
@@ -21,7 +21,8 @@ import type { Placements } from '../../types'
import { getNextActiveElement, isRTL } from '../../utils'
import type { Alignments, Directions } from './types'
-import { getPlacement } from './utils'
+import { getPlacement, getReferenceElement } from './utils'
+import { CFocusTrap } from '../focus-trap'
export interface CDropdownProps extends HTMLAttributes {
/**
@@ -160,6 +161,27 @@ export interface CDropdownProps extends HTMLAttributes
+ * Toggle dropdown
+ *
+ * Action
+ * Another Action
+ *
+ *
+ *
+ * @since 5.9.0
+ */
+ reference?: 'parent' | 'toggle' | HTMLElement | React.RefObject
+
/**
* Defines the visual variant of the React Dropdown
*/
@@ -203,6 +225,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
popper = true,
popperConfig,
portal = false,
+ reference = 'toggle',
variant = 'btn-group',
visible = false,
...rest
@@ -254,12 +277,20 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
}, [visible])
useEffect(() => {
- const toggleElement = dropdownToggleElement
+ return () => {
+ if (_visible) {
+ handleHide()
+ }
+ }
+ }, [])
+
+ useEffect(() => {
+ const referenceElement = getReferenceElement(reference, dropdownToggleElement, dropdownRef)
const menuElement = dropdownMenuRef.current
- if (allowPopperUse && menuElement && toggleElement && _visible) {
- initPopper(toggleElement, menuElement, computedPopperConfig)
+ if (allowPopperUse && menuElement && referenceElement && _visible) {
+ initPopper(referenceElement, menuElement, computedPopperConfig)
}
- }, [dropdownToggleElement])
+ }, [dropdownToggleElement, reference])
useEffect(() => {
if (pendingKeyDownEvent !== null) {
@@ -271,24 +302,28 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
const handleHide = useCallback(() => {
setVisible(false)
- const toggleElement = dropdownToggleElement
const menuElement = dropdownMenuRef.current
+ const toggleElement = dropdownToggleElement
if (allowPopperUse) {
destroyPopper()
}
- toggleElement?.removeEventListener('keydown', handleKeydown)
menuElement?.removeEventListener('keydown', handleKeydown)
+ toggleElement?.removeEventListener('keydown', handleKeydown)
- window.removeEventListener('mouseup', handleMouseUp)
+ window.removeEventListener('click', handleClick)
window.removeEventListener('keyup', handleKeyup)
onHide?.()
- }, [dropdownToggleElement, allowPopperUse, destroyPopper, onHide])
+ }, [allowPopperUse, dropdownToggleElement, destroyPopper, onHide])
const handleKeydown = useCallback((event: KeyboardEvent) => {
- if (dropdownMenuRef.current && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
+ if (!dropdownMenuRef.current) {
+ return
+ }
+
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
event.preventDefault()
const target = event.target as HTMLElement
const items = [
@@ -311,28 +346,40 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
dropdownToggleElement?.focus()
}
},
- [autoClose, handleHide]
+ [autoClose, dropdownToggleElement, handleHide]
)
- const handleMouseUp = useCallback(
- (event: Event) => {
+ const handleClick = useCallback(
+ (event: MouseEvent) => {
if (!dropdownToggleElement || !dropdownMenuRef.current) {
return
}
- if (dropdownToggleElement.contains(event.target as HTMLElement)) {
+ if ((event as MouseEvent).button === 2) {
+ return
+ }
+
+ const composedPath = event.composedPath()
+ const isOnToggle = composedPath.includes(dropdownToggleElement)
+ const isOnMenu = composedPath.includes(dropdownMenuRef.current)
+
+ if (isOnToggle) {
+ return
+ }
+
+ const target = event.target as HTMLElement | null
+ const FORM_TAG_RE = /^(input|select|option|textarea|form|button|label)$/i
+
+ if (isOnMenu && target && FORM_TAG_RE.test(target.tagName)) {
return
}
if (
autoClose === true ||
- (autoClose === 'inside' &&
- dropdownMenuRef.current.contains(event.target as HTMLElement)) ||
- (autoClose === 'outside' &&
- !dropdownMenuRef.current.contains(event.target as HTMLElement))
+ (autoClose === 'inside' && isOnMenu) ||
+ (autoClose === 'outside' && !isOnMenu)
) {
- setTimeout(() => handleHide(), 1)
- return
+ handleHide()
}
},
[autoClose, dropdownToggleElement, handleHide]
@@ -340,21 +387,22 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
const handleShow = useCallback(
(event?: KeyboardEvent) => {
- const toggleElement = dropdownToggleElement
const menuElement = dropdownMenuRef.current
+ const referenceElement = getReferenceElement(reference, dropdownToggleElement, dropdownRef)
+ const toggleElement = dropdownToggleElement
- if (toggleElement && menuElement) {
+ if (menuElement && referenceElement && toggleElement) {
setVisible(true)
if (allowPopperUse) {
- initPopper(toggleElement, menuElement, computedPopperConfig)
+ initPopper(referenceElement, menuElement, computedPopperConfig)
}
toggleElement.focus()
toggleElement.addEventListener('keydown', handleKeydown)
menuElement.addEventListener('keydown', handleKeydown)
- window.addEventListener('mouseup', handleMouseUp)
+ window.addEventListener('click', handleClick)
window.addEventListener('keyup', handleKeyup)
if (event && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
@@ -365,53 +413,71 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
}
},
[
- dropdownToggleElement,
allowPopperUse,
- initPopper,
computedPopperConfig,
+ dropdownToggleElement,
+ reference,
+ handleClick,
handleKeydown,
- handleMouseUp,
handleKeyup,
+ initPopper,
onShow,
]
)
- const contextValues = {
- alignment,
- container,
- dark,
- dropdownMenuRef,
- dropdownToggleRef,
- handleHide,
- handleShow,
- popper: allowPopperUse,
- portal,
- variant,
- visible: _visible,
- }
+ const contextValues = useMemo(
+ () => ({
+ alignment,
+ container,
+ dark,
+ dropdownMenuRef,
+ dropdownToggleRef,
+ handleHide,
+ handleShow,
+ popper: allowPopperUse,
+ portal,
+ variant,
+ visible: _visible,
+ }),
+ [
+ alignment,
+ container,
+ dark,
+ dropdownMenuRef,
+ dropdownToggleRef,
+ handleHide,
+ handleShow,
+ allowPopperUse,
+ portal,
+ variant,
+ _visible,
+ ]
+ )
return (
- {variant === 'input-group' ? (
- <>{children}>
- ) : (
-
- {children}
-
- )}
+
+ {variant === 'input-group' ? (
+ <>{children}>
+ ) : (
+
+ {children}
+
+ )}
+
)
}
diff --git a/packages/coreui-react/src/components/dropdown/CDropdownHeader.tsx b/packages/coreui-react/src/components/dropdown/CDropdownHeader.tsx
index 89e53673..1aff66e9 100644
--- a/packages/coreui-react/src/components/dropdown/CDropdownHeader.tsx
+++ b/packages/coreui-react/src/components/dropdown/CDropdownHeader.tsx
@@ -9,6 +9,7 @@ export interface CDropdownHeaderProps extends HTMLAttributes
* Component used for the root node. Either a string to use a HTML element or a component.
*/
as?: ElementType
+
/**
* A string of all className you want applied to the component.
*/
diff --git a/packages/coreui-react/src/components/dropdown/CDropdownItemPlain.tsx b/packages/coreui-react/src/components/dropdown/CDropdownItemPlain.tsx
index bc4ae0bb..7d489da3 100644
--- a/packages/coreui-react/src/components/dropdown/CDropdownItemPlain.tsx
+++ b/packages/coreui-react/src/components/dropdown/CDropdownItemPlain.tsx
@@ -9,6 +9,7 @@ export interface CDropdownItemPlainProps extends HTMLAttributes
* Component used for the root node. Either a string to use a HTML element or a component.
*/
as?: ElementType
+
/**
* A string of all className you want applied to the component.
*/
diff --git a/packages/coreui-react/src/components/dropdown/CDropdownMenu.tsx b/packages/coreui-react/src/components/dropdown/CDropdownMenu.tsx
index 59442d63..3ee88ad5 100644
--- a/packages/coreui-react/src/components/dropdown/CDropdownMenu.tsx
+++ b/packages/coreui-react/src/components/dropdown/CDropdownMenu.tsx
@@ -15,6 +15,7 @@ export interface CDropdownMenuProps extends HTMLAttributes {
* Enables pseudo element caret on toggler.
*/
caret?: boolean
+
/**
* Create a custom toggler which accepts any content.
*/
custom?: boolean
+
/**
* If a dropdown `variant` is set to `nav-item` then render the toggler as a
* link instead of a button.
@@ -24,12 +26,22 @@ export interface CDropdownToggleProps extends Omit {
* @since 5.0.0
*/
navLink?: boolean
+
/**
* Similarly, create split button dropdowns with virtually the same markup as
* single button dropdowns, but with the addition of `.dropdown-toggle-split`
* className for proper spacing around the dropdown caret.
*/
split?: boolean
+
+ /**
+ * Screen reader label for split button dropdown toggle.
+ *
+ * @default 'Toggle Dropdown'
+ * @since 5.9.0
+ */
+ splitLabel?: string
+
/**
* Sets which event handlers you'd like provided to your toggle prop. You can
* specify one trigger or an array of them.
@@ -46,6 +58,7 @@ export const CDropdownToggle: FC = ({
className,
navLink = true,
split,
+ splitLabel = 'Toggle Dropdown',
trigger = 'click',
...rest
}) => {
@@ -113,7 +126,7 @@ export const CDropdownToggle: FC = ({
return (
{children}
- {split && Toggle Dropdown}
+ {split && {splitLabel}}
)
}
@@ -124,6 +137,7 @@ CDropdownToggle.propTypes = {
className: PropTypes.string,
custom: PropTypes.bool,
split: PropTypes.bool,
+ splitLabel: PropTypes.string,
trigger: triggerPropType,
}
diff --git a/packages/coreui-react/src/components/dropdown/utils.ts b/packages/coreui-react/src/components/dropdown/utils.ts
index 8b4a213f..171fa0f7 100644
--- a/packages/coreui-react/src/components/dropdown/utils.ts
+++ b/packages/coreui-react/src/components/dropdown/utils.ts
@@ -1,3 +1,4 @@
+import React from 'react'
import type { Placement } from '@popperjs/core'
import type { Placements } from '../../types'
import type { Alignments, Breakpoints } from './types'
@@ -49,3 +50,23 @@ export const getPlacement = (
return _placement
}
+
+export const getReferenceElement = (
+ reference: 'parent' | 'toggle' | React.RefObject | HTMLElement,
+ dropdownToggleElement: HTMLElement | null,
+ dropdownRef: React.RefObject
+): HTMLElement | null => {
+ if (reference === 'parent') {
+ return dropdownRef.current
+ }
+
+ if (reference instanceof HTMLElement) {
+ return reference
+ }
+
+ if (reference instanceof Object && 'current' in reference) {
+ return reference.current
+ }
+
+ return dropdownToggleElement
+}
diff --git a/packages/coreui-react/src/components/focus-trap/utils.ts b/packages/coreui-react/src/components/focus-trap/utils.ts
index 8f9a76f0..92b4bae3 100644
--- a/packages/coreui-react/src/components/focus-trap/utils.ts
+++ b/packages/coreui-react/src/components/focus-trap/utils.ts
@@ -56,12 +56,6 @@ export const isElement = (object: unknown): object is Element => {
return false
}
- // Handle jQuery objects
- if ('jquery' in object && object.jquery !== undefined) {
- const jQueryObject = object as { [key: number]: Element }
- return isElement(jQueryObject[0])
- }
-
return 'nodeType' in object && typeof object.nodeType === 'number'
}
diff --git a/packages/docs/content/api/CDropdown.api.mdx b/packages/docs/content/api/CDropdown.api.mdx
index 765fbd96..ef211307 100644
--- a/packages/docs/content/api/CDropdown.api.mdx
+++ b/packages/docs/content/api/CDropdown.api.mdx
@@ -190,6 +190,30 @@ const myContainer = document.getElementById('my-container')
Renders the React Dropdown Menu using a React Portal, allowing it to escape the DOM hierarchy for improved positioning.
+
+ | reference#5.9.0+ |
+ {`toggle`} |
+ {`HTMLElement`}, {`'parent'`}, {`'toggle'`}, {`RefObject\`} |
+
+
+ |
+ Sets the reference element for positioning the React Dropdown Menu.
+
+{`toggle`} - The React Dropdown Toggle button (default).
+{`parent`} - The React Dropdown wrapper element.
+{`HTMLElement`} - A custom HTML element.
+{`React.RefObject`} - A custom reference element.
+
+
+ Toggle dropdown
+
+ Action
+ Another Action
+
+`} />
+ |
+
| variant# |
{`btn-group`} |
diff --git a/packages/docs/content/api/CDropdownToggle.api.mdx b/packages/docs/content/api/CDropdownToggle.api.mdx
index 1f6572e1..cd56fb6f 100644
--- a/packages/docs/content/api/CDropdownToggle.api.mdx
+++ b/packages/docs/content/api/CDropdownToggle.api.mdx
@@ -145,6 +145,16 @@ import CDropdownToggle from '@coreui/react/src/components/dropdown/CDropdownTogg
Similarly, create split button dropdowns with virtually the same markup as single button dropdowns, but with the addition of {`.dropdown-toggle-split`} className for proper spacing around the dropdown caret.
+
+ | splitLabel#5.9.0+ |
+ {`Toggle Dropdown`} |
+ {`string`} |
+
+
+ |
+ Screen reader label for split button dropdown toggle.
+ |
+
| trigger# |
{`click`} |
diff --git a/packages/docs/content/components/dropdown/examples/DropdownDropendExample.tsx b/packages/docs/content/components/dropdown/examples/DropdownDropendExample.tsx
index e9d0656e..a6a1bd68 100644
--- a/packages/docs/content/components/dropdown/examples/DropdownDropendExample.tsx
+++ b/packages/docs/content/components/dropdown/examples/DropdownDropendExample.tsx
@@ -24,7 +24,7 @@ export const DropdownDropendExample = () => {
Small split button
-
+
Action
Another action
diff --git a/packages/docs/content/components/dropdown/examples/DropdownDropstartExample.tsx b/packages/docs/content/components/dropdown/examples/DropdownDropstartExample.tsx
index 276b5cff..195cd05e 100644
--- a/packages/docs/content/components/dropdown/examples/DropdownDropstartExample.tsx
+++ b/packages/docs/content/components/dropdown/examples/DropdownDropstartExample.tsx
@@ -25,7 +25,7 @@ export const DropdownDropstartExample = () => {
-
+
Action
Another action
diff --git a/packages/docs/content/components/dropdown/examples/DropdownOptionsAutoCloseBehaviorExample.tsx b/packages/docs/content/components/dropdown/examples/DropdownOptionsAutoCloseBehaviorExample.tsx
new file mode 100644
index 00000000..23d90df6
--- /dev/null
+++ b/packages/docs/content/components/dropdown/examples/DropdownOptionsAutoCloseBehaviorExample.tsx
@@ -0,0 +1,41 @@
+import React from 'react'
+import { CDropdown, CDropdownItem, CDropdownMenu, CDropdownToggle } from '@coreui/react'
+
+export const DropdownOptionsAutoCloseBehaviorExample = () => {
+ return (
+
+
+ Default dropdown
+
+ Action
+ Another action
+ Something else here
+
+
+
+ Clickable inside
+
+ Action
+ Another action
+ Something else here
+
+
+
+ Clickable outside
+
+ Action
+ Another action
+ Something else here
+
+
+
+ Manual close
+
+ Action
+ Another action
+ Something else here
+
+
+
+ )
+}
diff --git a/packages/docs/content/components/dropdown/examples/DropdownOptionsExample.tsx b/packages/docs/content/components/dropdown/examples/DropdownOptionsExample.tsx
new file mode 100644
index 00000000..688797e1
--- /dev/null
+++ b/packages/docs/content/components/dropdown/examples/DropdownOptionsExample.tsx
@@ -0,0 +1,36 @@
+import React from 'react'
+import { CButton, CDropdown, CDropdownItem, CDropdownMenu, CDropdownToggle } from '@coreui/react'
+
+export const DropdownOptionsExample = () => {
+ return (
+
+
+ Offset
+
+ Action
+ Another action
+ Something else here
+
+
+
+
+ Portal
+
+
+
+
+ Reference
+
+
+ Action
+ Another action
+ Something else here
+
+
+
+ )
+}
diff --git a/packages/docs/content/components/dropdown/index.mdx b/packages/docs/content/components/dropdown/index.mdx
index c5890f31..b0e8ba47 100644
--- a/packages/docs/content/components/dropdown/index.mdx
+++ b/packages/docs/content/components/dropdown/index.mdx
@@ -172,6 +172,22 @@ Put a form within a dropdown menu, or make it into a dropdown menu.
+## Dropdown options
+
+Use `offset` to displace the dropdown from its default position. The value is a string with two numbers separated by a comma, e.g. `offset={[10, 20]}`. Use `portal` property to render dropdowns in `body` instead of the parent element. This helps to avoid any overflow or z-index issues.
+
+
+
+### Auto close behavior
+
+By default, dropdowns are closed when clicking outside of the dropdown menu or the toggle button. You can change this behavior with the `autoClose` property. Set `autoClose` to:
+
+- `true` - Close on clicks inside or outside of the React.js dropdown menu.
+- `false` - Disable auto-close; close manually by setting the `visible={false}` (also not closed by `Escape`).
+- `'inside'` - Close only when clicking inside the React.js dropdown menu.
+- `'outside'` - Close only when clicking outside the React.js dropdown menu.
+
+
## API
diff --git a/packages/docs/package.json b/packages/docs/package.json
index 400d494a..54647ee2 100644
--- a/packages/docs/package.json
+++ b/packages/docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@coreui/react-docs",
- "version": "5.8.0",
+ "version": "5.9.0",
"private": true,
"description": "",
"homepage": "https://coreui.io/react/",
@@ -30,8 +30,8 @@
"@coreui/icons-react": "^2.3.0",
"@coreui/react-chartjs": "^3.0.0",
"@coreui/utils": "^2.0.2",
- "@docsearch/css": "^3.9.0",
- "@docsearch/react": "^3.9.0",
+ "@docsearch/css": "^4.0.1",
+ "@docsearch/react": "^4.0.1",
"@mdx-js/mdx": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@stackblitz/sdk": "^1.11.0",
@@ -58,7 +58,7 @@
"react-imask": "^7.6.1",
"react-markdown": "^10.1.0",
"rimraf": "^6.0.1",
- "sass": "^1.91.0",
+ "sass": "^1.92.1",
"showdown": "^2.1.0"
},
"devDependencies": {
diff --git a/packages/docs/src/components/Seo.tsx b/packages/docs/src/components/Seo.tsx
index 1d1763f3..befabf25 100644
--- a/packages/docs/src/components/Seo.tsx
+++ b/packages/docs/src/components/Seo.tsx
@@ -154,7 +154,7 @@ const SEO = ({ title, description, name, image, article, pro }: SEOProps) => {
'@type': 'WebPage',
'@id': seo.url.replace('docs//', 'docs/'),
},
- version: pro ? '5.17.1' : '5.8.0',
+ version: pro ? '5.17.1' : '5.9.0',
proficiencyLevel: 'Beginner',
},
]
diff --git a/packages/docs/src/styles/search.scss b/packages/docs/src/styles/search.scss
index fb794847..16fa476c 100644
--- a/packages/docs/src/styles/search.scss
+++ b/packages/docs/src/styles/search.scss
@@ -19,7 +19,9 @@
// stylelint-disable selector-class-pattern
:root {
--docsearch-primary-color: var(--cui-primary);
+ --docsearch-muted-color: var(--cui-secondary-color);
--docsearch-logo-color: var(--cui-primary);
+ --docsearch-key-color: var(--cui-secondary-color);
}
@include color-mode(dark, true) {
@@ -43,7 +45,6 @@
}
.DocSearch-Container {
- --docsearch-muted-color: var(--cui-secondary-color);
--docsearch-hit-shadow: none;
position: fixed;
@@ -74,7 +75,8 @@
@include box-shadow($input-box-shadow);
@include transition($input-transition);
- &:focus {
+ &:focus,
+ &:hover {
color: $input-focus-color;
background-color: $input-focus-bg;
border-color: $input-focus-border-color;
@@ -87,10 +89,6 @@
}
}
- &:hover:not(:disabled):not([readonly])::file-selector-button {
- background-color: $form-file-button-hover-bg;
- }
-
@include media-breakpoint-down(md) {
&,
&:hover,
@@ -109,32 +107,29 @@
.DocSearch-Button-Keys {
min-width: 0;
padding: 0 .25rem;
- background: rgba($black, .125);
+ background: var(--cui-secondary-bg);
@include border-radius(.25rem);
}
.DocSearch-Button-Key {
- top: 0;
width: auto;
- height: 1.5rem;
- padding: 0 .125rem;
- margin-right: 0;
- font-size: .875rem;
+ padding: 0;
background: none;
+ border: 0;
box-shadow: none;
-}
-.DocSearch-Commands-Key {
- padding-left: 1px;
- font-size: .875rem;
- background-color: rgba($black, .1);
- background-image: none;
- box-shadow: none;
+ &:first-child {
+ margin-right: 0;
+ }
}
-.DocSearch-Form {
- @include border-radius(var(--cui-border-radius));
-}
+// .DocSearch-Commands-Key {
+// padding-left: 1px;
+// font-size: .875rem;
+// background-color: rgba($black, .1);
+// background-image: none;
+// box-shadow: none;
+// }
.DocSearch-Hits {
mark {