Skip to content

Instantly share code, notes, and snippets.

@delucis
Last active May 9, 2026 11:22
Show Gist options
  • Select an option

  • Save delucis/1a5c731981a91966d0a8cfed07cc397b to your computer and use it in GitHub Desktop.

Select an option

Save delucis/1a5c731981a91966d0a8cfed07cc397b to your computer and use it in GitHub Desktop.
dataset utility

This small utility demonstrates transforming an object to data-* attributes for use in server templating. The data-* attributes match how a browser maps to JS, so you can use it and get back your original keys on the client from an element’s dataset property.

For example, in an Astro component:

---
import { dataset } from './dataset';

const data = { Example: "value", count: 10, backgroundColor: '#fff' };

const props = dataset(data);
// { 'data--example': 'value', 'data-count': 10, 'data-background-color': '#fff' }
---

<div id="example" {...props}>Example</div>

And a script could read these back:

const el = document.getElementById('example');
el.dataset.
       // ^ Example
       //   count
       //   backgroundColor

N.B. There’s no way to serialize a number in HTML, so the count property in the example above returns a string on the client.

/** Convert a string’s casing to kebab case following the algorithm used for data attributes. */
type DatasetDashCase<S> = S extends `${infer C}${infer T}`
? C extends Capitalize<C>
? `-${Uncapitalize<C>}${DatasetDashCase<T>}`
: `${C}${DatasetDashCase<T>}`
: S extends Symbol
? never
: S;
/** Generic “prettify” utility to unwrap types. */
type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
/** Convert a string to a `data-*` attribute. */
type DataSetKey<Key extends symbol | string | number> =
`data-${DatasetDashCase<Key>}`;
/** Map an object’s keys to `data-*` attribute style naming. */
type DataSet<Props> = Prettify<{
[Key in keyof Props as DataSetKey<Key>]: Props[Key];
}>;
/** Convert a key to a `data-*` attribute. */
const toDataSetKey = <S extends string>(str: S): DataSetKey<S> =>
`data-${
str.replaceAll(
/([A-Z])/g,
(char) => `-${char.toLowerCase()}`,
) as DatasetDashCase<S>
}`;
/**
* Convert an object to a `data-*` attribute object for server templating.
*
* @example
* dataset({ Value: 10, backgroundColor: 'orange' });
* // => { 'data--value': 10, 'data-background-color': 'orange' }
*/
export const dataset = <
P extends Record<string, string | number | boolean | null | undefined>,
>(
props: P,
) =>
Object.fromEntries(
Object.entries(props).map(([key, value]) => [toDataSetKey(key), value]),
) as DataSet<P>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment