diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/table/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/table/demos.mdx
index c09061ab36d..bed3a379913 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/components/table/demos.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/components/table/demos.mdx
@@ -52,6 +52,24 @@ It's also possible to use accordion to expand the table with more rows.
+##### Collapse all rows at once
+
+You can collapse all expanded rows by sending a ref to the `collapseAllHandleRef` prop and calling the `.current()` function on your ref.
+
+```jsx
+const myTableCollapseAll = React.useRef<() => void>()
+
+return (
+
+
+
+ {/* ... your table code */}
+
+)
+```
+
### Table with sticky header
diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/table/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/table/properties.mdx
index 786c9f7a57e..02ab1450ac9 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/components/table/properties.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/components/table/properties.mdx
@@ -9,6 +9,7 @@ showTabs: true
| Properties | Description |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accordion` | _(optional)_ set to `true` if you have one or more rows that contains an accordion content. Defaults to `false`. |
+| `collapseAllHandleRef` | _(optional)_ ref handle to collapse all expanded accordion rows. Send in a ref and use `.current()` to collapse all rows. Defaults to `undefined`. |
| `border` | _(optional)_ use `true` to show borders between table data cells. Defaults to `false`. |
| `outline` | _(optional)_ use `true` to show a outline border around the table. Defaults to `false`. |
| `sticky` | _(optional)_ use `true` to enable a sticky Table header. Or use `css-position` to enable the CSS based scroll behavior. Defaults to `false`. |
diff --git a/packages/dnb-eufemia/src/components/table/Table.tsx b/packages/dnb-eufemia/src/components/table/Table.tsx
index 8f348138f83..4fb53841da9 100644
--- a/packages/dnb-eufemia/src/components/table/Table.tsx
+++ b/packages/dnb-eufemia/src/components/table/Table.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useEffect } from 'react'
import classnames from 'classnames'
import Context from '../../shared/Context'
import Provider from '../../shared/Provider'
@@ -79,6 +79,13 @@ export type TableProps = {
* Default: null.
*/
fixed?: boolean
+
+ /**
+ * ref handle to collapse all expanded accordion rows. Send in a ref and use `.current()` to collapse all rows.
+ *
+ * Default: `undefined`
+ */
+ collapseAllHandleRef?: React.MutableRefObject<() => void>
} & StickyTableHeaderProps
export type TableAllProps = TableProps &
@@ -116,11 +123,21 @@ const Table = (componentProps: TableAllProps) => {
outline,
accordion,
accordionChevronPlacement, // eslint-disable-line
+ collapseAllHandleRef,
...props
} = allProps
const { elementRef } = useStickyHeader(allProps)
const { trCountRef, rerenderAlias } = useHandleOddEven({ children })
+ const collapseTrCallbacks = React.useRef<(() => void)[]>([])
+
+ useEffect(() => {
+ if (collapseAllHandleRef) {
+ collapseAllHandleRef.current = () => {
+ collapseTrCallbacks.current.forEach((callback) => callback())
+ }
+ }
+ }, [collapseAllHandleRef])
const skeletonClasses = createSkeletonClass('font', skeleton, context)
const spacingClasses = createSpacingClasses(props)
@@ -133,6 +150,7 @@ const Table = (componentProps: TableAllProps) => {
value={{
trCountRef,
rerenderAlias,
+ collapseTrCallbacks,
allProps: {
...allProps,
...context.getTranslation(componentProps).Table,
diff --git a/packages/dnb-eufemia/src/components/table/TableAccordion.tsx b/packages/dnb-eufemia/src/components/table/TableAccordion.tsx
index fea3facc273..7c8c9e9dae3 100644
--- a/packages/dnb-eufemia/src/components/table/TableAccordion.tsx
+++ b/packages/dnb-eufemia/src/components/table/TableAccordion.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useEffect } from 'react'
import classnames from 'classnames'
import Button from '../button/Button'
import IconPrimary from '../icon/IconPrimary'
@@ -12,22 +12,33 @@ import TableAccordionTd from './TableAccordionTd'
import TableAccordionTr from './TableAccordionTr'
import type { TableAccordionTdProps } from './TableAccordionTd'
import type { TableAccordionTrProps } from './TableAccordionTr'
+import type { TableTrProps } from './TableTr'
type TableAccordionContentProps =
| TableAccordionTdProps
| TableAccordionTrProps
-export function useTableAccordion({
- children,
- className,
- props,
- expanded,
- disabled,
- noAnimation,
- onClick,
- onOpened,
- onClosed,
-}) {
+type TableAccordionProps = {
+ count: number
+}
+
+export function TableAccordion(
+ allProps: TableAccordionProps &
+ TableTrProps &
+ React.TableHTMLAttributes
+) {
+ const {
+ children,
+ className,
+ expanded,
+ disabled,
+ noAnimation,
+ onClick,
+ onOpened,
+ onClosed,
+ count,
+ ...props
+ } = allProps
const tableContext = React.useContext(TableContext)
const [trIsOpen, setOpen] = React.useState(() => {
@@ -45,10 +56,6 @@ export function useTableAccordion({
const [trIsHover, setHover] = React.useState(false)
const [trHadClick, setHadClick] = React.useState(false)
- if (!tableContext?.allProps?.accordion) {
- return null
- }
-
let headerContent = React.Children.toArray(children)
const addExpandIcon = (icon) => {
@@ -71,6 +78,18 @@ export function useTableAccordion({
accordionContent.length !== 0 &&
accordionContent.every((element) => React.isValidElement(element))
+ useEffect(() => {
+ if (
+ hasAccordionContent &&
+ tableContext?.collapseTrCallbacks?.current &&
+ count
+ ) {
+ tableContext.collapseTrCallbacks.current[count] = () => {
+ setOpen(false)
+ }
+ }
+ }, [count, tableContext?.collapseTrCallbacks, hasAccordionContent])
+
const trParams =
!disabled && hasAccordionContent
? {
@@ -141,8 +160,8 @@ export function useTableAccordion({
)
- function onKeydownHandler(event: KeyboardEvent) {
- switch (keycode(event)) {
+ function onKeydownHandler(event: React.SyntheticEvent) {
+ switch (keycode(event.nativeEvent)) {
case 'space':
case 'enter':
{
@@ -166,7 +185,7 @@ export function useTableAccordion({
setHadClick(false)
}
function toggleOpenTr(
- event: MouseEvent,
+ event: React.SyntheticEvent,
allowInteractiveElement = false
) {
const target = event.target as HTMLElement
diff --git a/packages/dnb-eufemia/src/components/table/TableTr.tsx b/packages/dnb-eufemia/src/components/table/TableTr.tsx
index 82d9840a405..b0ee80136d7 100644
--- a/packages/dnb-eufemia/src/components/table/TableTr.tsx
+++ b/packages/dnb-eufemia/src/components/table/TableTr.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import classnames from 'classnames'
-import { useTableAccordion } from './TableAccordion'
+import { TableAccordion } from './TableAccordion'
import { TableContext } from './TableContext'
import TableAccordionTr from './TableAccordionTr'
@@ -68,18 +68,11 @@ export default function Tr(
const {
variant,
noWrap,
- expanded,
- disabled,
- noAnimation,
- onClick,
- onOpened,
- onClosed,
- children,
className: _className,
- ...props
+ ...accordionProps
} = componentProps
- const { currentVariant, isLast } = useHandleTrVariant({
+ const { currentVariant, isLast, count } = useHandleTrVariant({
variant,
})
@@ -91,27 +84,28 @@ export default function Tr(
_className
)
- const accordionTr = useTableAccordion({
- className,
- children,
- props,
+ const tableContext = React.useContext(TableContext)
+ if (tableContext?.allProps?.accordion) {
+ return (
+
+ )
+ }
+
+ const {
expanded,
disabled,
noAnimation,
onClick,
onOpened,
onClosed,
- })
+ ...trProps
+ } = accordionProps
- if (accordionTr) {
- return accordionTr
- }
-
- return (
-