Skip to content

Conversation

KoolADE85
Copy link
Contributor

This PR refactors Tabs to follow the same pattern as the other DCC components: Typescript, function components, with CSS in a sidecar file.

A few other improvements along the way:

  • dash-renderer exports Typescript interface for window.dash_component_api (Tabs uses this api internally)
  • allow components to specify a DashComponent as a prop type (in addition to a generic ReactNode)
    • extract-meta.js comprehends this the same way as ReactNode
    • Python will not raise an exception when passing a component to a prop typed as DashComponent.
    • Within a component, Typescript now understands that a DashComponent contains props, namespace, etc.

@KoolADE85 KoolADE85 force-pushed the feature/dcc-refactor-tabs branch from 522b8c9 to 577158a Compare October 17, 2025 20:26
Comment on lines 220 to 237
const tabContainerClassNames = [
'tab-container',
vertical ? 'tab-container--vert' : null,
props.className,
].filter(Boolean);

const tabContentClassNames = [
'tab-content',
vertical ? 'tab-content--vert' : null,
props.content_className,
].filter(Boolean);

const tabParentClassNames = [
'tab-parent',
vertical ? ' tab-parent--vert' : null,
isAboveBreakpoint ? ' tab-parent--above-breakpoint' : null,
props.parent_className,
].filter(Boolean);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this filter pattern is very efficient compared to regular if += in a useMemo in a direct string concat

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started using this pattern since I noticed a few places where null & undefined became part of the className. This was a compact way to prevent that.
Also, it seems more readable to me to have one className per line instead of string concats with ternary operators (and prettier somehow makes that "uglier", lol).

I put it in a useMemo, as you suggested. What do you think of this? If you still prefer an if statement for each, I'm happy to switch to that format, but it's twice as many code lines.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more about the performance, altho it probably doesn't matter much in this case, but in this you end up with 2x array traversal (filter+join) vs a couple ifs, the footprint is just not on the same level of complexity.

Comment on lines 15 to 21
export interface DashComponentApi {
ExternalWrapper: typeof ExternalWrapper;
DashContext: typeof DashContext;
useDashContext: typeof useDashContext;
getLayout: (componentPathOrId: DashLayoutPath | string) => any;
stringifyId: typeof stringifyId;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The branch is out of sync with dev, the api changed and devtool was added. Might be worth to sync the branches now to prevent further conflicts down the line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I synced with dev and updated the type here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants