Support Recharts v3
Describe the bug
https://github.com/recharts/recharts/releases
Affected component/components
Charts
How to reproduce
Clone the chart.tsx components which throw several errors.
Codesandbox/StackBlitz link
No response
Logs
System Info
-
Before submitting
- [x] I've made research efforts and searched the documentation
- [x] I've searched for existing issues
This happens due to Charts component referring heavily to internal props of Recharts, which have now been removed.
As a consequence, our UI app which uses the shadcn-ui Charts component, and where we are also using those internal props such as payload, label, item and index, completely fails to build.
Error: src/components/charts/job-durations.tsx(303,36): error TS2741: Property 'payload' is missing in type '{}' but required in type 'Pick<Props, "payload" | "verticalAlign">'.
Error: src/components/ui/chart.tsx(116,3): error TS2339: Property 'payload' does not exist on type 'Omit<Props<ValueType, NameType>, PropertiesReadFromContext> & { active?: boolean | undefined; includeHidden?: boolean | undefined; ... 17 more ...; axisId?: AxisId | undefined; } & ClassAttributes<...> & HTMLAttributes<...> & { ...; }'.
Error: src/components/ui/chart.tsx(121,3): error TS2339: Property 'label' does not exist on type 'Omit<Props<ValueType, NameType>, PropertiesReadFromContext> & { active?: boolean | undefined; includeHidden?: boolean | undefined; ... 17 more ...; axisId?: AxisId | undefined; } & ClassAttributes<...> & HTMLAttributes<...> & { ...; }'.
Error: src/components/ui/chart.tsx(191,23): error TS7006: Parameter 'item' implicitly has an 'any' type.
Error: src/components/ui/chart.tsx(191,29): error TS7006: Parameter 'index' implicitly has an 'any' type.
Error: src/components/ui/chart.tsx(270,39): error TS2344: Type '"payload" | "verticalAlign"' does not satisfy the constraint '"string" | "filter" | "fill" | "values" | "children" | "className" | "suppressHydrationWarning" | "color" | "height" | "id" | "lang" | "max" | "media" | "method" | "min" | "name" | ... 430 more ... | "onBBoxUpdate"'.
Type '"payload"' is not assignable to type '"string" | "filter" | "fill" | "values" | "children" | "className" | "suppressHydrationWarning" | "color" | "height" | "id" | "lang" | "max" | "media" | "method" | "min" | "name" | ... 430 more ... | "onBBoxUpdate"'.
Error: src/components/ui/chart.tsx(276,17): error TS2339: Property 'length' does not exist on type '{}'.
Error: src/components/ui/chart.tsx(288,16): error TS2339: Property 'map' does not exist on type '{}'.
Error: src/components/ui/chart.tsx(288,21): error TS7006: Parameter 'item' implicitly has an 'any' type.
here the updated code until we get an official fix :)
Gist link: https://gist.github.com/noxify/92bc410cc2d01109f4160002da9a61e5
Tested it locally with the "Chart Area - Interactive" and it seems to work, there was an error on hover. This is now fixed.
"use client"
import * as React from "react"
import * as RechartsPrimitive from "recharts"
import type { LegendPayload } from "recharts/types/component/DefaultLegendContent"
import {
NameType,
Payload,
ValueType,
} from "recharts/types/component/DefaultTooltipContent"
import type { Props as LegendProps } from "recharts/types/component/Legend"
import { TooltipContentProps } from "recharts/types/component/Tooltip"
import { cn } from "@/lib/utils"
// Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: "", dark: ".dark" } as const
export type ChartConfig = {
[k in string]: {
label?: React.ReactNode
icon?: React.ComponentType
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<keyof typeof THEMES, string> }
)
}
type ChartContextProps = {
config: ChartConfig
}
export type CustomTooltipProps = TooltipContentProps<ValueType, NameType> & {
className?: string
hideLabel?: boolean
hideIndicator?: boolean
indicator?: "line" | "dot" | "dashed"
nameKey?: string
labelKey?: string
labelFormatter?: (
label: TooltipContentProps<number, string>["label"],
payload: TooltipContentProps<number, string>["payload"]
) => React.ReactNode
formatter?: (
value: number | string,
name: string,
item: Payload<number | string, string>,
index: number,
payload: ReadonlyArray<Payload<number | string, string>>
) => React.ReactNode
labelClassName?: string
color?: string
}
export type ChartLegendContentProps = {
className?: string
hideIcon?: boolean
verticalAlign?: LegendProps["verticalAlign"]
payload?: LegendPayload[]
nameKey?: string
}
const ChartContext = React.createContext<ChartContextProps | null>(null)
function useChart() {
const context = React.useContext(ChartContext)
if (!context) {
throw new Error("useChart must be used within a <ChartContainer />")
}
return context
}
function ChartContainer({
id,
className,
children,
config,
...props
}: React.ComponentProps<"div"> & {
config: ChartConfig
children: React.ComponentProps<
typeof RechartsPrimitive.ResponsiveContainer
>["children"]
}) {
const uniqueId = React.useId()
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
return (
<ChartContext.Provider value={{ config }}>
<div
data-slot="chart"
data-chart={chartId}
className={cn(
"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
className
)}
{...props}
>
<ChartStyle id={chartId} config={config} />
<RechartsPrimitive.ResponsiveContainer>
{children}
</RechartsPrimitive.ResponsiveContainer>
</div>
</ChartContext.Provider>
)
}
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
([, config]) => config.theme || config.color
)
if (!colorConfig.length) {
return null
}
return (
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color
return color ? ` --color-${key}: ${color};` : null
})
.join("\n")}
}
`
)
.join("\n"),
}}
/>
)
}
const ChartTooltip = RechartsPrimitive.Tooltip
function ChartTooltipContent({
active,
payload,
label,
className,
indicator = "dot",
hideLabel = false,
hideIndicator = false,
labelFormatter,
formatter,
labelClassName,
color,
nameKey,
labelKey,
}: CustomTooltipProps) {
const { config } = useChart()
const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
return null
}
const [item] = payload
const key = `${labelKey || item?.dataKey || item?.name || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const value = (() => {
const v =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label ?? label
: itemConfig?.label
return typeof v === "string" || typeof v === "number" ? v : undefined
})()
if (labelFormatter) {
return (
<div className={cn("font-medium", labelClassName)}>
{labelFormatter(value, payload)}
</div>
)
}
if (!value) {
return null
}
return <div className={cn("font-medium", labelClassName)}>{value}</div>
}, [
label,
labelFormatter,
payload,
hideLabel,
labelClassName,
config,
labelKey,
])
if (!active || !payload?.length) {
return null
}
const nestLabel = payload.length === 1 && indicator !== "dot"
return (
<div
className={cn(
"border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
className
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const indicatorColor = color || item.payload.fill || item.color
return (
<div
key={item.dataKey}
className={cn(
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
indicator === "dot" && "items-center"
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
}
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center"
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
</div>
</>
)}
</div>
)
})}
</div>
</div>
)
}
const ChartLegend = RechartsPrimitive.Legend
function ChartLegendContent({
className,
hideIcon = false,
payload,
verticalAlign = "bottom",
nameKey,
}: ChartLegendContentProps) {
const { config } = useChart()
if (!payload?.length) {
return null
}
return (
<div
className={cn(
"flex items-center justify-center gap-4",
verticalAlign === "top" ? "pb-3" : "pt-3",
className
)}
>
{payload.map((item) => {
const key = `${nameKey || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
return (
<div
key={item.value}
className={cn(
"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
)}
>
{itemConfig?.icon && !hideIcon ? (
<itemConfig.icon />
) : (
<div
className="h-2 w-2 shrink-0 rounded-[2px]"
style={{
backgroundColor: item.color,
}}
/>
)}
{itemConfig?.label}
</div>
)
})}
</div>
)
}
// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
config: ChartConfig,
payload: unknown,
key: string
) {
if (typeof payload !== "object" || payload === null) {
return undefined
}
const payloadPayload =
"payload" in payload &&
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
: undefined
let configLabelKey: string = key
if (
key in payload &&
typeof payload[key as keyof typeof payload] === "string"
) {
configLabelKey = payload[key as keyof typeof payload] as string
} else if (
payloadPayload &&
key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
) {
configLabelKey = payloadPayload[
key as keyof typeof payloadPayload
] as string
}
return configLabelKey in config
? config[configLabelKey]
: config[key as keyof typeof config]
}
export {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
ChartStyle,
}
Just updated due to the change with 3.0.2
Also exporting types for the custom types. Reason why the types is needed...
import type { CustomTooltipProps } from '@/components/ui/chart'
<ChartTooltip
cursor={false}
content={(props: CustomTooltipProps) => (
<ChartTooltipContent {...props} hideIndicator hideLabel />
)}
/>
@rubixvi you are a god send thank you
@noxify Huge thanks!
"use client" import * as React from "react" import * as RechartsPrimitive from "recharts" import type { LegendPayload } from "recharts/types/component/DefaultLegendContent" import { NameType, Payload, ValueType, } from "recharts/types/component/DefaultTooltipContent" import type { Props as LegendProps } from "recharts/types/component/Legend" import { TooltipContentProps } from "recharts/types/component/Tooltip" import { cn } from "@/lib/utils" // Format: { THEME_NAME: CSS_SELECTOR } const THEMES = { light: "", dark: ".dark" } as const export type ChartConfig = { [k in string]: { label?: React.ReactNode icon?: React.ComponentType } & ( | { color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> } ) } type ChartContextProps = { config: ChartConfig } const ChartContext = React.createContext<ChartContextProps | null>(null) function useChart() { const context = React.useContext(ChartContext) if (!context) { throw new Error("useChart must be used within a <ChartContainer />") } return context } function ChartContainer({ id, className, children, config, ...props }: React.ComponentProps<"div"> & { config: ChartConfig children: React.ComponentProps< typeof RechartsPrimitive.ResponsiveContainer >["children"] }) { const uniqueId = React.useId() const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` return ( <ChartContext.Provider value={{ config }}> <div data-slot="chart" data-chart={chartId} className={cn( "[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden", className )} {...props} > <ChartStyle id={chartId} config={config} /> <RechartsPrimitive.ResponsiveContainer> {children} </RechartsPrimitive.ResponsiveContainer> </div> </ChartContext.Provider> ) } const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { const colorConfig = Object.entries(config).filter( ([, config]) => config.theme || config.color ) if (!colorConfig.length) { return null } return ( <style dangerouslySetInnerHTML={{ __html: Object.entries(THEMES) .map( ([theme, prefix]) => ` ${prefix} [data-chart=${id}] { ${colorConfig .map(([key, itemConfig]) => { const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.color return color ? ` --color-${key}: ${color};` : null }) .join("\n")} } ` ) .join("\n"), }} /> ) } const ChartTooltip = RechartsPrimitive.Tooltip type CustomTooltipProps = TooltipContentProps<ValueType, NameType> & { className?: string hideLabel?: boolean hideIndicator?: boolean indicator?: "line" | "dot" | "dashed" nameKey?: string labelKey?: string labelFormatter?: ( label: TooltipContentProps<number, string>["label"], payload: TooltipContentProps<number, string>["payload"] ) => React.ReactNode formatter?: ( value: number | string, name: string, item: Payload<number | string, string>, index: number, payload: ReadonlyArray<Payload<number | string, string>> ) => React.ReactNode labelClassName?: string color?: string } function ChartTooltipContent({ active, payload, label, className, indicator = "dot", hideLabel = false, hideIndicator = false, labelFormatter, formatter, labelClassName, color, nameKey, labelKey, }: CustomTooltipProps) { const { config } = useChart() const tooltipLabel = React.useMemo(() => { if (hideLabel || !payload?.length) { return null } const [item] = payload const key = `${labelKey || item?.dataKey || item?.name || "value"}` const itemConfig = getPayloadConfigFromPayload(config, item, key) const value = !labelKey && typeof label === "string" ? config[label as keyof typeof config]?.label || label : itemConfig?.label if (labelFormatter) { return ( <div className={cn("font-medium", labelClassName)}> {labelFormatter(value, payload)} </div> ) } if (!value) { return null } return <div className={cn("font-medium", labelClassName)}>{value}</div> }, [ label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey, ]) if (!active || !payload?.length) { return null } const nestLabel = payload.length === 1 && indicator !== "dot" return ( <div className={cn( "border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl", className )} > {!nestLabel ? tooltipLabel : null} <div className="grid gap-1.5"> {payload.map((item, index) => { const key = `${nameKey || item.name || item.dataKey || "value"}` const itemConfig = getPayloadConfigFromPayload(config, item, key) const indicatorColor = color || item.payload.fill || item.color return ( <div key={item.dataKey} className={cn( "[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5", indicator === "dot" && "items-center" )} > {formatter && item?.value !== undefined && item.name ? ( formatter(item.value, item.name, item, index, item.payload) ) : ( <> {itemConfig?.icon ? ( <itemConfig.icon /> ) : ( !hideIndicator && ( <div className={cn( "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", { "h-2.5 w-2.5": indicator === "dot", "w-1": indicator === "line", "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed", "my-0.5": nestLabel && indicator === "dashed", } )} style={ { "--color-bg": indicatorColor, "--color-border": indicatorColor, } as React.CSSProperties } /> ) )} <div className={cn( "flex flex-1 justify-between leading-none", nestLabel ? "items-end" : "items-center" )} > <div className="grid gap-1.5"> {nestLabel ? tooltipLabel : null} <span className="text-muted-foreground"> {itemConfig?.label || item.name} </span> </div> {item.value && ( <span className="text-foreground font-mono font-medium tabular-nums"> {item.value.toLocaleString()} </span> )} </div> </> )} </div> ) })} </div> </div> ) } const ChartLegend = RechartsPrimitive.Legend type ChartLegendContentProps = { className?: string hideIcon?: boolean verticalAlign?: LegendProps["verticalAlign"] payload?: LegendPayload[] nameKey?: string } function ChartLegendContent({ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey, }: ChartLegendContentProps) { const { config } = useChart() if (!payload?.length) { return null } return ( <div className={cn( "flex items-center justify-center gap-4", verticalAlign === "top" ? "pb-3" : "pt-3", className )} > {payload.map((item) => { const key = `${nameKey || item.dataKey || "value"}` const itemConfig = getPayloadConfigFromPayload(config, item, key) return ( <div key={item.value} className={cn( "[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3" )} > {itemConfig?.icon && !hideIcon ? ( <itemConfig.icon /> ) : ( <div className="h-2 w-2 shrink-0 rounded-[2px]" style={{ backgroundColor: item.color, }} /> )} {itemConfig?.label} </div> ) })} </div> ) } // Helper to extract item config from a payload. function getPayloadConfigFromPayload( config: ChartConfig, payload: unknown, key: string ) { if (typeof payload !== "object" || payload === null) { return undefined } const payloadPayload = "payload" in payload && typeof payload.payload === "object" && payload.payload !== null ? payload.payload : undefined let configLabelKey: string = key if ( key in payload && typeof payload[key as keyof typeof payload] === "string" ) { configLabelKey = payload[key as keyof typeof payload] as string } else if ( payloadPayload && key in payloadPayload && typeof payloadPayload[key as keyof typeof payloadPayload] === "string" ) { configLabelKey = payloadPayload[ key as keyof typeof payloadPayload ] as string } return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config] } export { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle, }Here you go
I just added the code to my chart.tsx and it doesn't work somehow.
I also added the react-is in my package.json so what am I doing wrong?
code was just updated again...
Change:
const value =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label || label
: itemConfig?.label
to
const value = (() => {
const v =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label ?? label
: itemConfig?.label
return typeof v === "string" || typeof v === "number" ? v : undefined
})()
export type CustomTooltipProps = TooltipContentProps<ValueType, NameType> & {
className?: string
hideLabel?: boolean
hideIndicator?: boolean
indicator?: "line" | "dot" | "dashed"
nameKey?: string
labelKey?: string
labelFormatter?: (
label: TooltipContentProps<number, string>["label"],
payload: TooltipContentProps<number, string>["payload"]
) => React.ReactNode
formatter?: (
value: number | string,
name: string,
item: Payload<number | string, string>,
index: number,
payload: ReadonlyArray<Payload<number | string, string>>
) => React.ReactNode
labelClassName?: string
color?: string
}
This was moved to the top from my previous comment. This type might be used in several cases. For example:
const formatter: CustomTooltipProps["formatter"] = (value, name) => [value, name]
<ChartTooltip
labelFormatter={formatLongDate}
formatter={formatter}
content={(props: CustomTooltipProps) => (
<ChartTooltipContent {...props} indicator="dashed" />
)}
/>
Otherwise, you'll end up getting complaints about type safety 'any'.
Does anyone else get the following Error randomly?
Error: Cannot destructure property 'activeIndex' of 'z(...)' as it is undefined.
3 | <ChartTooltip
| ^
184 | cursor={false}
185 | content={(props: CustomTooltipProps) => (
186 | <ChartTooltipContent {...props} hideIndicator hideLabel />
I have used the chart.tsx shown here in the discussion and the tooltip like this:
<ChartTooltip
cursor={false}
content={(props: CustomTooltipProps) => (
<ChartTooltipContent {...props} hideIndicator hideLabel />
)}
/>
Does anyone else get the following Error randomly?
Error: Cannot destructure property 'activeIndex' of 'z(...)' as it is undefined.3 | <ChartTooltip | ^ 184 | cursor={false} 185 | content={(props: CustomTooltipProps) => ( 186 | <ChartTooltipContent {...props} hideIndicator hideLabel />I have used the chart.tsx shown here in the discussion and the tooltip like this:
<ChartTooltip cursor={false} content={(props: CustomTooltipProps) => ( <ChartTooltipContent {...props} hideIndicator hideLabel /> )} />
You can use:
<ChartTooltip
cursor={false}
content={(props) => (
<ChartTooltipContent {...props} hideIndicator hideLabel />
)}
/>
See if that helps, however, you will get some type safety warning.
Unless we set up guards for the tooltip, haven't had time to go through that and set up all the guards yet.
Does anyone else get the following Error randomly?
Error: Cannot destructure property 'activeIndex' of 'z(...)' as it is undefined.3 | <ChartTooltip | ^ 184 | cursor={false} 185 | content={(props: CustomTooltipProps) => ( 186 | <ChartTooltipContent {...props} hideIndicator hideLabel />I have used the chart.tsx shown here in the discussion and the tooltip like this:
<ChartTooltip cursor={false} content={(props: CustomTooltipProps) => ( <ChartTooltipContent {...props} hideIndicator hideLabel /> )} />You can use:
<ChartTooltip cursor={false} content={(props) => ( <ChartTooltipContent {...props} hideIndicator hideLabel /> )} />See if that helps, however, you will get some type safety warning.
Unless we set up guards for the tooltip, haven't had time to go through that and set up all the guards yet.
That didn't work however when I just import Tooltip from recharts where I build my chart, it works fine...
That works, depending on how your data is structured and how you've designed your charts.
I've tested in a live environment, in development Tooltip type may be fine. But when you're deploying it, it may crash depending on how your custom component is structured.
@rubixvi, your ChartTooltipContent indicators are not consuming the border/bg variables and thus never showing.
- border-(--color-border) bg-(--color-bg)
+ border-[var(--color-border)] bg-[var(--color-bg)]
edit: @rubixvi, sorry the issue is main. Tooltips are showing, but the indicator (dot/line/dashed) is not.
@rubixvi, your ChartTooltipContent indicators are not consuming the border/bg variables and thus never showing.
- border-(--color-border) bg-(--color-bg) + border-[var(--color-border)] bg-[var(--color-bg)]
What are you on about... All my charts are working. I think you quoted the wrong thing.
Not consuming the border colour is not going to prevent a tool tip component from showing up.
I've pinned recharts to 2.15.4 for now. I've also added a callout on the docs page. @noxify @rubixvi thanks for the code examples. I'll take a look and start the upgrade.
Still errors, [email protected] does not fix this.
@noxify @rubixvi What am I doing wrong?
item.payload seems to be not existing or any!?
label is of type any
@henningsieh any chance to provide the link to your repo or at least a minimal repro with your implementation?
Could take a look in the evening but need more information about your implementation.
Feel free to ping me via discord --> noxy88
Hi, check this link
- https://intentui.com/docs/components/visualizations/chart
- https://intentui.com/docs/components/visualizations/area-chart
Its using Recharts v3 you can use the source for inspiration
PS. intentui is like shadcn but for react-aria
Any recent progress or changes?
Any recent progress or changes?
Does anyone else get the following Error randomly?
Error: Cannot destructure property 'activeIndex' of 'z(...)' as it is undefined.3 | <ChartTooltip | ^ 184 | cursor={false} 185 | content={(props: CustomTooltipProps) => ( 186 | <ChartTooltipContent {...props} hideIndicator hideLabel />I have used the chart.tsx shown here in the discussion and the tooltip like this:
<ChartTooltip cursor={false} content={(props: CustomTooltipProps) => ( <ChartTooltipContent {...props} hideIndicator hideLabel /> )} />
Im hitting this issue, only way I could figure out a fix was patch-package
diff --git a/es6/component/Tooltip.js b/es6/component/Tooltip.js
index 08a1416abff8def9df9b45468f34720f553fe117..4a8746ae9a2a66ac7072fb7c53fc02c54f31d082 100644
--- a/es6/component/Tooltip.js
+++ b/es6/component/Tooltip.js
@@ -99,7 +99,7 @@ export function Tooltip(outsideProps) {
var {
activeIndex,
isActive
- } = useAppSelector(state => selectIsTooltipActive(state, tooltipEventType, trigger, defaultIndexAsString));
+ } = useAppSelector(state => selectIsTooltipActive(state, tooltipEventType, trigger, defaultIndexAsString)) || { activeIndex: null, isActive: false };
var payloadFromRedux = useAppSelector(state => selectTooltipPayload(state, tooltipEventType, trigger, defaultIndexAsString));
var labelFromRedux = useAppSelector(state => selectActiveLabel(state, tooltipEventType, trigger, defaultIndexAsString));
var coordinate = useAppSelector(state => selectActiveCoordinate(state, tooltipEventType, trigger, defaultIndexAsString));
Why not merge to main?