diff --git a/.changeset/spicy-games-arrive.md b/.changeset/spicy-games-arrive.md
new file mode 100644
index 0000000000..aaee5b1b3a
--- /dev/null
+++ b/.changeset/spicy-games-arrive.md
@@ -0,0 +1,5 @@
+---
+"shadcn-ui": minor
+---
+
+add support for jsx
diff --git a/apps/www/config/docs.ts b/apps/www/config/docs.ts
index c5a6180171..e41fdf49d8 100644
--- a/apps/www/config/docs.ts
+++ b/apps/www/config/docs.ts
@@ -78,6 +78,11 @@ export const docsConfig: DocsConfig = {
href: "/docs/changelog",
items: [],
},
+ {
+ title: "About",
+ href: "/docs/about",
+ items: [],
+ },
],
},
{
diff --git a/apps/www/content/docs/about.mdx b/apps/www/content/docs/about.mdx
new file mode 100644
index 0000000000..ab523185c5
--- /dev/null
+++ b/apps/www/content/docs/about.mdx
@@ -0,0 +1,20 @@
+---
+title: About
+description: Powered by amazing open source projects.
+---
+
+## About
+
+[ui.shadcn.com](https://ui.shadcn.com) is a project by [shadcn](https://shadcn.com).
+
+## Credits
+
+- [Radix UI](https://radix-ui.com) - For the primitives.
+- [Vercel](https://vercel.com) - Where I host all my projects.
+- [Shu Ding](https://shud.in) - The typography style is adapted from his work on Nextra.
+- [Cal](https://cal.com) - Where I copied the styles for the first component: the `Button`.
+- [cmdk](https://cmdk.paco.me) - For the `` component.
+
+## License
+
+MIT © [shadcn](https://shadcn.com)
diff --git a/apps/www/content/docs/changelog.mdx b/apps/www/content/docs/changelog.mdx
index 000d41bd7d..0d08561294 100644
--- a/apps/www/content/docs/changelog.mdx
+++ b/apps/www/content/docs/changelog.mdx
@@ -4,6 +4,48 @@ description: Latest updates and announcements.
toc: false
---
+## July 2023 - JavaScript
+
+This project and the components are written in TypeScript. We recommend using TypeScript for your project as well.
+
+However we provide a JavaScript version of the components as well. The JavaScript version is available via the [cli](/docs/cli).
+
+```txt
+Would you like to use TypeScript (recommended)? no
+```
+
+To opt-out of TypeScript, you can use the `tsx` flag in your `components.json` file.
+
+```json {10} title="components.json"
+{
+ "style": "default",
+ "tailwind": {
+ "config": "tailwind.config.js",
+ "css": "src/app/globals.css",
+ "baseColor": "zinc",
+ "cssVariables": true
+ },
+ "rsc": false,
+ "tsx": false,
+ "aliases": {
+ "utils": "~/lib/utils",
+ "components": "~/components"
+ }
+}
+```
+
+To configure import aliases, you can use the following `jsconfig.json`:
+
+```json {4} title="jsconfig.json"
+{
+ "compilerOptions": {
+ "paths": {
+ "@/*": ["./*"]
+ }
+ }
+}
+```
+
## June 2023 - New CLI, Styles and more
I have a lot of updates to share with you today:
diff --git a/apps/www/content/docs/index.mdx b/apps/www/content/docs/index.mdx
index 341365f825..90f7ed4ef7 100644
--- a/apps/www/content/docs/index.mdx
+++ b/apps/www/content/docs/index.mdx
@@ -65,11 +65,3 @@ But hey, let me know if you do. I'd love to see what you build.
-
-## Credits
-
-- [Radix UI](https://radix-ui.com) - For the primitives.
-- [Vercel](https://vercel.com) - Where I host all my projects.
-- [Shu Ding](https://shud.in) - The typography style is adapted from his work on Nextra.
-- [Cal](https://cal.com) - Where I copied the styles for the first component: the `Button`.
-- [cmdk](https://cmdk.paco.me) - For the `` component.
diff --git a/apps/www/content/docs/installation/astro.mdx b/apps/www/content/docs/installation/astro.mdx
index 62204248ab..1e84289240 100644
--- a/apps/www/content/docs/installation/astro.mdx
+++ b/apps/www/content/docs/installation/astro.mdx
@@ -88,6 +88,7 @@ npx shadcn-ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
+Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › ./src/styles/globals.css
diff --git a/apps/www/content/docs/installation/gatsby.mdx b/apps/www/content/docs/installation/gatsby.mdx
index 87ac29fbb1..a680cd2fa3 100644
--- a/apps/www/content/docs/installation/gatsby.mdx
+++ b/apps/www/content/docs/installation/gatsby.mdx
@@ -84,6 +84,7 @@ npx shadcn-ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
+Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › ./src/styles/globals.css
diff --git a/apps/www/content/docs/installation/index.mdx b/apps/www/content/docs/installation/index.mdx
index 914abfd7a0..309e830652 100644
--- a/apps/www/content/docs/installation/index.mdx
+++ b/apps/www/content/docs/installation/index.mdx
@@ -3,7 +3,9 @@ title: Installation
description: How to install dependencies and structure your app.
---
-
+## Frameworks
+
+
-## Other frameworks
+## TypeScript
-I'm looking for help writing guides for other frameworks. Help me write those guides by [opening an PR](https://github.com/shadcn/ui).
+This project and the components are written in TypeScript. We recommend using TypeScript for your project as well.
+
+However we provide a JavaScript version of the components as well. The JavaScript version is available via the [cli](/docs/cli).
+
+To opt-out of TypeScript, you can use the `tsx` flag in your `components.json` file.
+
+```json {10} title="components.json"
+{
+ "style": "default",
+ "tailwind": {
+ "config": "tailwind.config.js",
+ "css": "src/app/globals.css",
+ "baseColor": "zinc",
+ "cssVariables": true
+ },
+ "rsc": false,
+ "tsx": false,
+ "aliases": {
+ "utils": "~/lib/utils",
+ "components": "~/components"
+ }
+}
+```
+
+To configure import aliases, you can use the following `jsconfig.json`:
+
+```json {4} title="jsconfig.json"
+{
+ "compilerOptions": {
+ "paths": {
+ "@/*": ["./*"]
+ }
+ }
+}
+```
diff --git a/apps/www/content/docs/installation/next.mdx b/apps/www/content/docs/installation/next.mdx
index c7a0cbb6ed..0fe520f5fd 100644
--- a/apps/www/content/docs/installation/next.mdx
+++ b/apps/www/content/docs/installation/next.mdx
@@ -26,6 +26,7 @@ npx shadcn-ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
+Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › app/globals.css
diff --git a/apps/www/content/docs/installation/remix.mdx b/apps/www/content/docs/installation/remix.mdx
index b6d925fe88..2b484a1009 100644
--- a/apps/www/content/docs/installation/remix.mdx
+++ b/apps/www/content/docs/installation/remix.mdx
@@ -26,6 +26,7 @@ npx shadcn-ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
+Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › app/tailwind.css
diff --git a/apps/www/content/docs/installation/vite.mdx b/apps/www/content/docs/installation/vite.mdx
index d369a49e94..bf1195037a 100644
--- a/apps/www/content/docs/installation/vite.mdx
+++ b/apps/www/content/docs/installation/vite.mdx
@@ -71,6 +71,7 @@ npx shadcn-ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
+Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › src/index.css
diff --git a/apps/www/public/schema.json b/apps/www/public/schema.json
index 99fbf179d1..14c922a8fb 100644
--- a/apps/www/public/schema.json
+++ b/apps/www/public/schema.json
@@ -27,6 +27,9 @@
"rsc": {
"type": "boolean"
},
+ "tsx": {
+ "type": "boolean"
+ },
"aliases": {
"type": "object",
"properties": {
diff --git a/packages/cli/package.json b/packages/cli/package.json
index c79b8e1308..72b409908f 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -45,6 +45,9 @@
},
"dependencies": {
"@antfu/ni": "^0.21.4",
+ "@babel/core": "^7.22.1",
+ "@babel/parser": "^7.22.6",
+ "@babel/plugin-transform-typescript": "^7.22.5",
"chalk": "5.2.0",
"commander": "^10.0.0",
"cosmiconfig": "^8.1.3",
@@ -52,16 +55,20 @@
"execa": "^7.0.0",
"fs-extra": "^11.1.0",
"https-proxy-agent": "^6.2.0",
+ "lodash.template": "^4.5.0",
"node-fetch": "^3.3.0",
"ora": "^6.1.2",
"prompts": "^2.4.2",
+ "recast": "^0.23.2",
"ts-morph": "^18.0.0",
"tsconfig-paths": "^4.2.0",
"zod": "^3.20.2"
},
"devDependencies": {
+ "@types/babel__core": "^7.20.1",
"@types/diff": "^5.0.3",
"@types/fs-extra": "^11.0.1",
+ "@types/lodash.template": "^4.5.1",
"@types/prompts": "^2.4.2",
"rimraf": "^4.1.3",
"tsup": "^6.6.3",
diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts
index 1f20961396..46ef641575 100644
--- a/packages/cli/src/commands/add.ts
+++ b/packages/cli/src/commands/add.ts
@@ -143,7 +143,7 @@ export const add = new Command()
}
for (const file of item.files) {
- const filePath = path.resolve(targetDir, file.name)
+ let filePath = path.resolve(targetDir, file.name)
// Run transformers.
const content = await transform({
@@ -153,6 +153,10 @@ export const add = new Command()
baseColor,
})
+ if (!config.tsx) {
+ filePath = filePath.replace(/\.tsx$/, ".jsx")
+ }
+
await fs.writeFile(filePath, content)
}
diff --git a/packages/cli/src/commands/diff.ts b/packages/cli/src/commands/diff.ts
index 214d84f371..37308eaa89 100644
--- a/packages/cli/src/commands/diff.ts
+++ b/packages/cli/src/commands/diff.ts
@@ -166,7 +166,7 @@ async function diffComponent(
baseColor,
})
- const patch = diffLines(registryContent, fileContent)
+ const patch = diffLines(registryContent as string, fileContent)
if (patch.length > 1) {
changes.push({
file: file.name,
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
index f21931a03c..598ab6d60e 100644
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -2,7 +2,6 @@ import { existsSync, promises as fs } from "fs"
import path from "path"
import {
DEFAULT_COMPONENTS,
- DEFAULT_TAILWIND_BASE_COLOR,
DEFAULT_TAILWIND_CONFIG,
DEFAULT_TAILWIND_CSS,
DEFAULT_UTILS,
@@ -23,6 +22,7 @@ import * as templates from "@/src/utils/templates"
import chalk from "chalk"
import { Command } from "commander"
import { execa } from "execa"
+import template from "lodash.template"
import ora from "ora"
import prompts from "prompts"
import * as z from "zod"
@@ -86,6 +86,16 @@ export async function promptForConfig(
const baseColors = await getRegistryBaseColors()
const options = await prompts([
+ {
+ type: "toggle",
+ name: "typescript",
+ message: `Would you like to use ${highlight(
+ "TypeScript"
+ )} (recommended)?`,
+ initial: defaultConfig?.tsx ?? true,
+ active: "yes",
+ inactive: "no",
+ },
{
type: "select",
name: "style",
@@ -115,7 +125,9 @@ export async function promptForConfig(
{
type: "toggle",
name: "tailwindCssVariables",
- message: `Do you want to use ${highlight("CSS variables")} for colors?`,
+ message: `Would you like to use ${highlight(
+ "CSS variables"
+ )} for colors?`,
initial: defaultConfig?.tailwind.cssVariables ?? true,
active: "yes",
inactive: "no",
@@ -158,6 +170,7 @@ export async function promptForConfig(
cssVariables: options.tailwindCssVariables,
},
rsc: options.rsc,
+ tsx: options.typescript,
aliases: {
utils: options.utils,
components: options.components,
@@ -213,12 +226,14 @@ export async function runInit(cwd: string, config: Config) {
}
}
+ const extension = config.tsx ? "ts" : "js"
+
// Write tailwind config.
await fs.writeFile(
config.resolvedPaths.tailwindConfig,
config.tailwind.cssVariables
- ? templates.TAILWIND_CONFIG_WITH_VARIABLES
- : templates.TAILWIND_CONFIG,
+ ? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension })
+ : template(templates.TAILWIND_CONFIG)({ extension }),
"utf8"
)
@@ -236,8 +251,8 @@ export async function runInit(cwd: string, config: Config) {
// Write cn file.
await fs.writeFile(
- `${config.resolvedPaths.utils}.ts`,
- templates.UTILS,
+ `${config.resolvedPaths.utils}.${extension}`,
+ extension === "ts" ? templates.UTILS : templates.UTILS_JS,
"utf8"
)
diff --git a/packages/cli/src/utils/get-config.ts b/packages/cli/src/utils/get-config.ts
index 54b056c4b5..b6376d7029 100644
--- a/packages/cli/src/utils/get-config.ts
+++ b/packages/cli/src/utils/get-config.ts
@@ -22,6 +22,7 @@ export const rawConfigSchema = z
$schema: z.string().optional(),
style: z.string(),
rsc: z.coerce.boolean().default(false),
+ tsx: z.coerce.boolean().default(true),
tailwind: z.object({
config: z.string(),
css: z.string(),
@@ -89,6 +90,6 @@ export async function getRawConfig(cwd: string): Promise
{
return rawConfigSchema.parse(configResult.config)
} catch (error) {
- throw new Error(`Invald configuration found in ${cwd}/components.json.`)
+ throw new Error(`Invalid configuration found in ${cwd}/components.json.`)
}
}
diff --git a/packages/cli/src/utils/templates.ts b/packages/cli/src/utils/templates.ts
index 523ef7171b..5af47c2f49 100644
--- a/packages/cli/src/utils/templates.ts
+++ b/packages/cli/src/utils/templates.ts
@@ -6,14 +6,22 @@ export function cn(...inputs: ClassValue[]) {
}
`
+export const UTILS_JS = `import { clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs) {
+ return twMerge(clsx(inputs))
+}
+`
+
export const TAILWIND_CONFIG = `/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
content: [
- './pages/**/*.{ts,tsx}',
- './components/**/*.{ts,tsx}',
- './app/**/*.{ts,tsx}',
- './src/**/*.{ts,tsx}',
+ './pages/**/*.{<%- extension %>,<%- extension %>x}',
+ './components/**/*.{<%- extension %>,<%- extension %>x}',
+ './app/**/*.{<%- extension %>,<%- extension %>x}',
+ './src/**/*.{<%- extension %>,<%- extension %>x}',
],
theme: {
container: {
@@ -47,10 +55,10 @@ export const TAILWIND_CONFIG_WITH_VARIABLES = `/** @type {import('tailwindcss').
module.exports = {
darkMode: ["class"],
content: [
- './pages/**/*.{ts,tsx}',
- './components/**/*.{ts,tsx}',
- './app/**/*.{ts,tsx}',
- './src/**/*.{ts,tsx}',
+ './pages/**/*.{<%- extension %>,<%- extension %>x}',
+ './components/**/*.{<%- extension %>,<%- extension %>x}',
+ './app/**/*.{<%- extension %>,<%- extension %>x}',
+ './src/**/*.{<%- extension %>,<%- extension %>x}',
],
theme: {
container: {
diff --git a/packages/cli/src/utils/transformers/index.ts b/packages/cli/src/utils/transformers/index.ts
index ef38cbae43..b5699d71e6 100644
--- a/packages/cli/src/utils/transformers/index.ts
+++ b/packages/cli/src/utils/transformers/index.ts
@@ -5,6 +5,7 @@ import { Config } from "@/src/utils/get-config"
import { registryBaseColorSchema } from "@/src/utils/registry/schema"
import { transformCssVars } from "@/src/utils/transformers/transform-css-vars"
import { transformImport } from "@/src/utils/transformers/transform-import"
+import { transformJsx } from "@/src/utils/transformers/transform-jsx"
import { transformRsc } from "@/src/utils/transformers/transform-rsc"
import { Project, ScriptKind, type SourceFile } from "ts-morph"
import * as z from "zod"
@@ -16,11 +17,11 @@ export type TransformOpts = {
baseColor?: z.infer
}
-export type Transformer = (
+export type Transformer