diff --git a/.changeset/funny-seahorses-refuse.md b/.changeset/funny-seahorses-refuse.md
new file mode 100644
index 00000000..4a7b5b38
--- /dev/null
+++ b/.changeset/funny-seahorses-refuse.md
@@ -0,0 +1,5 @@
+---
+"preact-render-to-string": patch
+---
+
+Transform attribute names to proper casing
diff --git a/package-lock.json b/package-lock.json
index fe9beeb4..e3964f99 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
 	"name": "preact-render-to-string",
-	"version": "6.0.0",
+	"version": "6.0.1",
 	"lockfileVersion": 2,
 	"requires": true,
 	"packages": {
 		"": {
 			"name": "preact-render-to-string",
-			"version": "6.0.0",
+			"version": "6.0.1",
 			"license": "MIT",
 			"dependencies": {
 				"pretty-format": "^3.8.0"
diff --git a/src/index.js b/src/index.js
index d610ca9c..6450ec52 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,9 @@
-import { encodeEntities, styleObjToCss, UNSAFE_NAME, XLINK } from './util';
+import {
+	encodeEntities,
+	styleObjToCss,
+	transformAttributeName,
+	UNSAFE_NAME
+} from './util';
 import { options, h, Fragment } from 'preact';
 import {
 	CHILDREN,
@@ -307,15 +312,15 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
 				break;
 
 			default: {
-				if (isSvgMode && XLINK.test(name)) {
-					name = name.toLowerCase().replace(XLINK_REPLACE_REGEX, 'xlink:');
-				} else if (UNSAFE_NAME.test(name)) {
+				if (UNSAFE_NAME.test(name)) {
 					continue;
 				} else if ((name[4] === '-' || name === 'draggable') && v != null) {
 					// serialize boolean aria-xyz or draggable attribute values as strings
 					// `draggable` is an enumerated attribute and not Boolean. A value of `true` or `false` is mandatory
 					// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/draggable
 					v += '';
+				} else {
+					name = transformAttributeName(name);
 				}
 			}
 		}
@@ -360,7 +365,6 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
 	return s + '>' + html + '</' + type + '>';
 }
 
-const XLINK_REPLACE_REGEX = /^xlink:?/;
 const SELF_CLOSING = new Set([
 	'area',
 	'base',
diff --git a/src/pretty.js b/src/pretty.js
index fd73431d..3a74df6e 100644
--- a/src/pretty.js
+++ b/src/pretty.js
@@ -5,6 +5,7 @@ import {
 	styleObjToCss,
 	getChildren,
 	createComponent,
+	transformAttributeName,
 	UNSAFE_NAME,
 	XLINK,
 	VOID_ELEMENTS
@@ -133,7 +134,6 @@ function _renderToStringPretty(
 				!nodeName.prototype ||
 				typeof nodeName.prototype.render !== 'function'
 			) {
-
 				// If a hook invokes setState() to invalidate the component during rendering,
 				// re-render it up to 25 times to allow "settling" of memoized states.
 				// Note:
@@ -149,7 +149,6 @@ function _renderToStringPretty(
 					rendered = nodeName.call(vnode.__c, props, cctx);
 				}
 			} else {
-
 				// c = new nodeName(props, context);
 				c = vnode.__c = new nodeName(props, cctx);
 				c.__v = vnode;
@@ -278,6 +277,8 @@ function _renderToStringPretty(
 				// <textarea value="a&b"> --> <textarea>a&amp;b</textarea>
 				propChildren = v;
 			} else if ((v || v === 0 || v === '') && typeof v !== 'function') {
+				name = transformAttributeName(name);
+
 				if (v === true || v === '') {
 					v = name;
 					// in non-xml mode, allow boolean attributes
diff --git a/src/util.js b/src/util.js
index c3a598e1..955e2df5 100644
--- a/src/util.js
+++ b/src/util.js
@@ -148,3 +148,23 @@ export function createComponent(vnode, context) {
 		__h: []
 	};
 }
+
+const DASHED_ATTRS = /^(acceptC|httpE|(clip|color|fill|font|glyph|marker|stop|stroke|text|vert)[A-Z])/;
+const CAMEL_ATTRS = /^(isP|viewB)/;
+const COLON_ATTRS = /^(xlink|xml|xmlns)([A-Z])/;
+
+const CAPITAL_REGEXP = /([A-Z])/g;
+
+export function transformAttributeName(name) {
+	if (CAMEL_ATTRS.test(name)) return name;
+
+	if (DASHED_ATTRS.test(name)) {
+		return name.replace(CAPITAL_REGEXP, '-$1').toLowerCase();
+	}
+
+	if (COLON_ATTRS.test(name)) {
+		return name.replace(CAPITAL_REGEXP, ':$1').toLowerCase();
+	}
+
+	return name.toLowerCase();
+}
diff --git a/test/render.test.js b/test/render.test.js
index 17213b5b..4a93e95e 100644
--- a/test/render.test.js
+++ b/test/render.test.js
@@ -128,6 +128,38 @@ describe('render', () => {
 			expect(rendered).to.equal(expected);
 		});
 
+		it('should decamelize attributes', () => {
+			let rendered = render(<img srcSet="foo.png, foo2.png 2x" />),
+				expected = `<img srcset="foo.png, foo2.png 2x"/>`;
+
+			expect(rendered).to.equal(expected);
+		});
+
+		it('should decamelize bool attributes', () => {
+			let rendered = render(
+					<link rel="preconnect" href="https://foo.com" crossOrigin />
+				),
+				expected = `<link rel="preconnect" href="https://foo.com" crossorigin/>`;
+
+			expect(rendered).to.equal(expected);
+		});
+
+		it('should dasherize certain attributes', () => {
+			let rendered = render(<meta httpEquiv="refresh" />),
+				expected = `<meta http-equiv="refresh"/>`;
+
+			expect(rendered).to.equal(expected);
+		});
+
+		it('should colonize/dasherize certain attributes & leave certain attributes camelized', () => {
+			let rendered = render(
+					<svg xmlSpace="preserve" viewBox="0 0 10 10" fillRule="nonzero" />
+				),
+				expected = `<svg xml:space="preserve" viewBox="0 0 10 10" fill-rule="nonzero"></svg>`;
+
+			expect(rendered).to.equal(expected);
+		});
+
 		it('should include boolean aria-* attributes', () => {
 			let rendered = render(<div aria-hidden aria-whatever={false} />),
 				expected = `<div aria-hidden="true" aria-whatever="false"></div>`;
@@ -321,7 +353,7 @@ describe('render', () => {
 
 		it('should render SVG elements', () => {
 			let rendered = render(
-				<svg>
+				<svg viewBox="0 0 100 100">
 					<image xlinkHref="#" />
 					<foreignObject>
 						<div xlinkHref="#" />
@@ -333,7 +365,7 @@ describe('render', () => {
 			);
 
 			expect(rendered).to.equal(
-				`<svg><image xlink:href="#"></image><foreignObject><div xlinkHref="#"></div></foreignObject><g><image xlink:href="#"></image></g></svg>`
+				`<svg viewBox="0 0 100 100"><image xlink:href="#"></image><foreignObject><div xlink:href="#"></div></foreignObject><g><image xlink:href="#"></image></g></svg>`
 			);
 		});
 	});