diff --git a/packages/astro/astro-jsx.d.ts b/packages/astro/astro-jsx.d.ts index 2f01aafe4..59ef899f2 100644 --- a/packages/astro/astro-jsx.d.ts +++ b/packages/astro/astro-jsx.d.ts @@ -507,7 +507,7 @@ declare namespace astroHTML.JSX { lang?: string | undefined | null; slot?: string | undefined | null; spellcheck?: 'true' | 'false' | boolean | undefined | null; - style?: string | undefined | null; + style?: string | Record | undefined | null; tabindex?: number | string | undefined | null; title?: string | undefined | null; translate?: 'yes' | 'no' | undefined | null; @@ -1017,7 +1017,7 @@ declare namespace astroHTML.JSX { method?: string | undefined | null; min?: number | string | undefined | null; name?: string | undefined | null; - style?: string | undefined | null; + style?: string | Record | undefined | null; target?: string | undefined | null; type?: string | undefined | null; width?: number | string | undefined | null; diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts index a1c47fa3e..368917b06 100644 --- a/packages/astro/src/runtime/server/index.ts +++ b/packages/astro/src/runtime/server/index.ts @@ -542,6 +542,9 @@ export function createAstro( const toAttributeString = (value: any, shouldEscape = true) => shouldEscape ? String(value).replace(/&/g, '&').replace(/"/g, '"') : value; +const kebab = (k: string) => k.toLowerCase() === k ? k : k.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`); +const toStyleString = (obj: Record) => Object.entries(obj).map(([k, v]) => `${kebab(k)}:${v}`).join(';') + const STATIC_DIRECTIVES = new Set(['set:html', 'set:text']); // A helper used to turn expressions into attribute key/value @@ -575,6 +578,16 @@ Make sure to use the static attribute syntax (\`${key}={value}\`) instead of the return markHTMLString(` ${key.slice(0, -5)}="${listValue}"`); } + // support object styles for better JSX compat + if (key === 'style' && typeof value === 'object') { + return markHTMLString(` ${key}="${toStyleString(value)}"`); + } + + // support `className` for better JSX compat + if (key === 'className') { + return markHTMLString(` class="${toAttributeString(value, shouldEscape)}"`); + } + // Boolean values only need the key if (value === true && (key.startsWith('data-') || htmlBooleanAttributes.test(key))) { return markHTMLString(` ${key}`);