DesignSystemProvider
The DesignSystemProvider
is a foundational component that should be placed at the root of your application. It provides the design system's theme to all components underneath it.
One of its most powerful features is the injectTrackingProps
prop, which allows you to intercept and modify the props of every component in the design system. This is incredibly useful for implementing cross-cutting concerns like analytics, custom event handling, or dynamic prop injection.
injectTrackingProps
The injectTrackingProps
function receives two arguments: props
(the original props passed to a component instance) and componentName
(the name of the component). You can then return a new set of props for that component.
Here is a basic example of how you could add analytics tracking to every onClick
event in your application:
const injectTrackingProps = (props, componentName) => { // Check if the component has an onClick prop if(props.onClick) { // Keep a reference to the original handler const originalOnClick = props.onClick; // Return a new props object return { ...props, // with our wrapped onClick handler onClick: (ev) => { // Call the original handler originalOnClick(ev); // And then trigger our analytics event trackClickEvent({ componentName, ...props }); }, }; } // If there's no onClick, return the original props return props;};<DesignSystemProvider injectTrackingProps={injectTrackingProps}> <App /></DesignSystemProvider>
Using injectTrackingProps
as a Hook
The injectTrackingProps
function is called in a component's render cycle, which means you can use React hooks within it, just like you would in a custom hook. This enables more advanced and flexible logic.
For example, you could create a useAnalyticsProps
hook that adds a tracking event to components that have a special trackOnClick
prop.
import { useCallback } from 'react';const useAnalyticsProps = (passedProps, componentName) => { // A simple "tracking" function for demonstration purposes. // In a real app, this would call your analytics provider. const trackEvent = (data) => { console.log('Analytics Event Fired:', data); }; const handleClick = useCallback((ev) => { // Fire our tracking event with some component data trackEvent({ component: componentName, text: passedProps.children, }); // Call the original onClick if it exists passedProps.onClick?.(ev); }, [passedProps.onClick, passedProps.children, componentName]); // We only want to add this behavior to components that opt-in with `trackOnClick` if ('trackOnClick' in passedProps) { // Exclude `trackOnClick` from the final props so it's not passed to the DOM element. const { trackOnClick, ...props } = passedProps; // Attach our new click handler. props.onClick = handleClick; // Return the modified props. return props; } // If `trackOnClick` is not present, return the original props without modification. return passedProps;};<DesignSystemProvider injectTrackingProps={useAnalyticsProps}> <App /></DesignSystemProvider>
Now, any design system component with the trackOnClick
prop will automatically have its onClick
event tracked.
<Button trackOnClick>Click Me</Button>
Adding Custom Props with TypeScript
You may have noticed that trackOnClick
is not a standard prop on our components. To make TypeScript aware of this and other custom props you want to use with injectTrackingProps
, you can use module augmentation.
Create a type declaration file in your project, for example src/types/design-system.d.ts
:
// types/design-system.d.tsimport '@hoverinc/design-system-react-web';declare module '@hoverinc/design-system-react-web' { // This extends the BaseProps interface from our design system interface BaseProps { trackOnClick?: boolean; // You can add any other custom props here // trackingId?: string; }}
Finally, ensure your tsconfig.json
includes this new declaration file. You can do this by adding it to the include
array:
{ "compilerOptions": { // ... }, "include": [ "src", "types/design-system.d.ts" ]}
This makes your custom props available on all design system components and provides type safety for your injectTrackingProps
implementation.