Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Universal solution for data attributes in React

I have some duplicating code across my project that looks like this:

function MyComp({prop1, prop2, ...restProps}) {
    
    // ...

    const dataAttributes = Object.keys(restProps).reduce((acc, key) => {
      if (key.startsWith('data-')) {
        acc[key] = restProps[key];
      }

      return acc;
    }, {});

    return (
        <div {...dataAttributes}>
            {/* ... */}
        </div>
    );
}

I'm thinking about automation of this behaviour (pass props that start with data- to the root element of the component if it's an html element).

Any thoughts?

like image 520
bniwredyc Avatar asked Oct 31 '25 22:10

bniwredyc


2 Answers

Maybe you just can create a custom component for the html tags you use, like RichDiv, RichSpan... It would be like:

const getDataAttributes = (inputProps = {}) => Object.keys(inputProps).reduce((acc, key) => {
      if (key.startsWith('data-')) {
        acc[key] = inputProps[key];
      }

      return acc;
    }, {});

function RichDiv({children, className, ...restProps}) {
    const dataAttributes = getDataAttributes(restProps);

    return (
        <div {...dataAttributes} className={className}>
            {children}
        </div>
    );
}

function RichSpan({children, className, ...restProps}) {
    const dataAttributes = getDataAttributes(restProps);

    return (
        <span {...dataAttributes} className={className}>
            {children}
        </span>
    );
}

You can add any other whitelisted prop like I did with className to the custom components or even improve the props filter function you made to make it return both data- attributes and other HTML common attributes. Then, you just import and use your RichDiv instead of vanilla div and so.

like image 94
Luis Gil Gutiérrez Avatar answered Nov 03 '25 10:11

Luis Gil Gutiérrez


The first and not very complex step might be the extraction of reducing part to a separate utility function like this:

export function extractDataAttributes(props) {
    return Object.keys(props).reduce((acc, key) => {
        if (key.startsWith("data-")) {
            acc[key] = props[key];
        }

        return acc;
    }, {});
}

Then you can use it in the following shorter way:

function MyComp({prop1, prop2, ...restProps}) {
    // ...
  
    return (
        <div {...extractDataAttributes(restProps)}>
            {/* ... */}
        </div>
    );
}

By doing so, you'll also explicitly mark that the resulting markup has data-attributes. On the other hand, there will be no unnecessary details.

If you find this solution insufficient at some point, it might be a good idea to use HOC looking inside its children and updating them. However, this approach might lower the explicitness of your code.

like image 30
Terbiy Avatar answered Nov 03 '25 10:11

Terbiy