Skip to content

Instantly share code, notes, and snippets.

@RobinMalfait
Last active January 4, 2023 19:36
Show Gist options
  • Star 52 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save RobinMalfait/a90e8651196c273dfa51eec0f43e1676 to your computer and use it in GitHub Desktop.
Save RobinMalfait/a90e8651196c273dfa51eec0f43e1676 to your computer and use it in GitHub Desktop.
Tailwind UI -> Valid React

Community based - Examples to React

DISCLAIMER: This is something a Tailwind UI user created. This also doesn't actually add all the functionality, however it will ensure that the markup is valid JSX. Search for todo and you will see all the alpine stuff that you can convert yourself.


WARNING: This doesn't work in Firefox because they don't allow to read from the clipboard. They only allow it in extensions.

How to use

  1. Create a bookmark in your browser where the url is set to the contents of bookmark.js 1.1. Copy bookmark.js

    1.2. Create a new bookmark in your browser. I am using Brave here.

    1.3. Paste in the contents

  2. Go to Tailwind UI

  3. Press the "Copy to clipboard" button on an example

  4. Press the bookmark

  5. You should receive an alert saying that it is either copied OR has an error.

  6. Profit.

javascript:window.navigator.clipboard.readText().then((data)=>{return window.navigator.clipboard.writeText(data .replace(/class=/g,"className=").replace(/ @([^"]*)=/g,(_all,group)=>` data-todo-at-${group.replace(/[.:]/g,"-")}=`).replace(/ x-([^ "]*)/g,(_all,group)=>` data-todo-x-${group.replace(/[.:]/g,"-")}`).replace(/<!--/g,"{/*").replace(/-->/g,"*/}").replace(/tabindex="([^"]*)"/g,"tabIndex={$1}").replace(/datetime=/g,"dateTime=").replace(/clip-rule=/g,"clipRule=").replace(/fill-rule=/g,"fillRule=").replace(/stroke-linecap=/g,"strokeLinecap=").replace(/stroke-width=/g,"strokeWidth=").replace(/stroke-linejoin=/g,"strokeLinejoin=").replace(/for=/g,"htmlFor=").replace(/ :(.*)=/g," data-todo-colon-$1=").replace(/href="#"/g,'href="/"').replace(/src="\//g,'src="https://tailwindui.com/').replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"").replace(/<(img|input|hr)([^>]*)>/g,"<$1$2 />").replace(/style="([^"]*)"/g,(_,style)=>{return `style={{${style.split(";").filter((pair)=>pair.trim().length).map((pair)=>pair.split(":").map((part)=>part.trim())).map(([key,value])=>[key.replace(/-(\w)/g,(_,v)=>v.toUpperCase()),JSON.stringify(value.match(/\d*px/)?parseFloat(value):value)].join(": ")).join(", ")}}}`}).trim()).then(()=>{alert("Copied to clipboard!")})}).catch((err)=>{console.log("[TAILWIND UI - Example -> React] Error:",err);alert("Bummer! Something went wrong... (psst, see devtools)")});
// Note this doesn't work as a bookmark, you need the bookmark (minified) version
javascript: window.navigator.clipboard
.readText()
.then((data) => {
return window.navigator.clipboard
.writeText(
data
// Replace `class=` with `className=`
.replace(/class=/g, "className=")
// Replace all attributes starting with @.
//
// E.g.: `@click.stop` -> `data-todo-at-stop`
.replace(
/ @([^"]*)=/g,
(_all, group) => ` data-todo-at-${group.replace(/[.:]/g, "-")}=`
)
// Replaces all attributes starting with x-.
//
// E.g.: `x-transition:enter` -> `data-todo-x-transition-enter`
.replace(
/ x-([^ "]*)/g,
(_all, group) => ` data-todo-x-${group.replace(/[.:]/g, "-")}`
)
// Replace html comments with JSX comments
.replace(/<!--/g, "{/*")
.replace(/-->/g, "*/}")
// Replace `tabindex="0"` with `tabIndex={0}`
.replace(/tabindex="([^"]*)"/g, "tabIndex={$1}")
// Replace `datetime` with `dateTime` for <time />
.replace(/datetime=/g, "dateTime=")
// Replace `clip-rule` with `clipRule` in svg's
.replace(/clip-rule=/g, "clipRule=")
// Replace `fill-rule` with `fillRule` in svg's
.replace(/fill-rule=/g, "fillRule=")
// Replace `stroke-linecap` with `strokeLinecap` in svg's
.replace(/stroke-linecap=/g, "strokeLinecap=")
// Replace `stroke-width` with `strokeWidth` in svg's
.replace(/stroke-width=/g, "strokeWidth=")
// Replace `stroke-linejoin` with `strokeLinejoin` in svg's
.replace(/stroke-linejoin=/g, "strokeLinejoin=")
// Replace `for` with `htmlFor` in forms
.replace(/for=/g, "htmlFor=")
// Replace all attributes starting with :.
//
// E.g.`:class="{ 'hidden': open, 'inline-flex': !open` ->
// `data-todo-colon-class="{ 'hidden': open, 'inline-flex': !open }"`
.replace(/ :(.*)=/g, " data-todo-colon-$1=")
// Replace `href="#"` with `href="/"` (Otherwise Create React App complains)
.replace(/href="#"/g, 'href="/"')
// Replace relative src paths with absolute src paths.
.replace(/src="\//g, 'src="https://tailwindui.com/')
// Drop scripts ¯\_(ツ)_/¯
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")
// Ensure img, input and hr tags are self closed
.replace(/<(img|input|hr)([^>]*)>/g, "<$1$2 />")
// Ensure we rewrite the style string to an object
.replace(/style="([^"]*)"/g, (_, style) => {
return `style={{${style
.split(";")
.filter((pair) => pair.trim().length)
.map((pair) => pair.split(":").map((part) => part.trim()))
.map(([key, value]) =>
[
key.replace(/-(\w)/g, (_, v) => v.toUpperCase()),
JSON.stringify(
value.match(/\d*px/) ? parseFloat(value) : value
),
].join(": ")
)
.join(", ")}}}`;
})
// Trim the whitespace!
.trim()
)
.then(() => {
alert("Copied to clipboard!");
});
})
.catch((err) => {
console.log("[TAILWIND UI - Example -> React] Error:", err);
alert("Bummer! Something went wrong... (psst, see devtools)");
});
@vvo
Copy link

vvo commented Mar 12, 2020

Hey thanks this is extremely useful :)

@vvo
Copy link

vvo commented Mar 12, 2020

@RobinMalfait and others, I made a small UI to explain how to use this, with an easy drag and drop button https://qlp8g.csb.app/

@rylandking
Copy link

Thank you for this, @RobinMalfait!

@JuanLuisGarciaBorrego
Copy link

JuanLuisGarciaBorrego commented Apr 20, 2020

Hello, thanks you!
How do you implement the effects in ReactJS?

<div className={`md:hidden ${showNav ? 'block' : 'hidden'} `}></div>

 {/*<!--
    Off-canvas menu overlay, show/hide based on off-canvas menu state.

   Entering: "transition-opacity ease-linear duration-300"
   From: "opacity-0"
  To: "opacity-100"
  Leaving: "transition-opacity ease-linear duration-300"
   From: "opacity-100"
   To: "opacity-0"
-->*/}

@JuanLuisGarciaBorrego
Copy link

@vvo thank you very much!!

@rgdelato
Copy link

Just a quick FYI, it might be worth adding a note that this snippet doesn't work in Firefox, at least as far as I can tell.

@ecklf
Copy link

ecklf commented Aug 14, 2020

Made a grease/tampermonkey script with minor modifications: Tailwind UI -> Valid React

Preview:
ezgif-4-37af9c68da35

@markitics
Copy link

This is great, thanks. I normally hide the bookmarks bar, so today I learned on Mac I can press Cmd-Shift-B (Ctrl-Shift-B on Windows) to toggle show/hide bookmark bar (in Chrome).

@stevecastaneda
Copy link

Couple to add that I noticed today:

// Replace `autocomplete` with `autoComplete` in inputs
.replace(/autocomplete=/g, "autoComplete=")

and...

// Replace `rows="0"` with `rows={0}` in textareas
.replace(/rows="([^"]*)"/g, "rows={$1}")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment