TW elements is a plugin that extends the functionality of the library with many interactive components.
In some dynamic components (like dropdowns or modals) we add custom JavaScript. However, they do not require any additional installation, all the necessary code is always included in the example and copied to any Tailwind project - it will work.
TW elements formats
TW elements, in order to meet the new, modular approach, allows the use of
ES
and UMD
formats. These formats will differ in
the way components are initialized and will be used in different cases.
When to use ES or UMD format?
If your application:
- is based on
modules
- uses
bundler
functionality - needs
treeshaking
the ES
format will be most suitable for you, otherwise
UMD
is the way to go.
What is the difference between TW elements ES and UMD formats?
In short, the way to initialize components. In order to allow bundlers to
perform proper treeshaking, we have moved component initialization to the
initTWE
method. TW elements in UMD
format will
work without adding more elements, but will lack treeshaking. TW Elements
in ES
format, on the other hand, allows components to be used
as separate modules, resulting in the much smaller build size.
About the initTWE
method
To use the initTWE method, you need to import it from the
tw-elements
, same as for components. You can provide a second
argument that will be an object with options that you want to pass to the
init method. The options object can contain the following properties:
-
allowReinits
- by default it's value is set tofalse
. By changing the value totrue
, theinitTWE
method won't check if components were already initialized. It can be helpful for example when using theTW elements
package with frameworks that use routing (for example Vue SPA) -
checkOtherImports
- by default the value is also set tofalse
. How does it work? IfinitTWE
finds a component that should be inited but has not been passed as an argument (for example, it finds a data attribute that would suggest that it should be initialized automatically), it will display a warning in a console. We encourage to use it in the last invocation ofinitTWE
method because it shows what inits are lacking at the current moment.
How to use the initTWE
method?
Import the method from the tw-elements
package inside your
project js
file and call it with the components you want to
initialize.
import { Input, initTWE } from "tw-elements";
initTWE({ Input }, { allowReinits: true });
1. Before starting the project make sure to install Node.js (LTS) and TailwindCSS.
2. Run the following command to install the package via NPM:
npm install tw-elements
3. TW elements is a plugin and should be included inside
tailwind.config.js
. It is also recommended to extend the
content
array with a js files pattern that loads dynamic
component classes. The final version of the config file should look like
this:
module.exports = {
content: [
"./src/**/*.{html,js}",
"./node_modules/tw-elements/js/**/*.js"
],
plugins: [require("tw-elements/plugin.cjs")],
darkMode: "class"
};
4. Include the following JavaScript file before the end of the body element. Keep in mind that the path to the file may be different depending on the file structure of your project.
<script
type="text/javascript"
src="../node_modules/tw-elements/dist/js/tw-elements.umd.min.js"></script>
Now, the library is ready to use and available via the global
twe
variable.
1. To start using MDB GO / CLI install it with one command:
npm install -g mdb-cli
2. Log into the CLI using your MDB account:
mdb login
3. Initialize a project and choose TW elements from the list:
mdb init tailwind-elements
4. Install the dependencies (inside the project directory):
npm install
5. Run the app:
npm start
6. Publish when you're ready:
mdb publish
Vite
Node.js version 16.17.0 + / 18.1.0 +
installed. Please
update if your package manager asks for it. If you are expecting issues
with vite.config.js
and you don't want to update the npm,
try using the 4.3.9
version of vite.
Vite (French word for "fast", pronounced /vit/) is a build tool that aims to provide a faster and leaner development experience for modern web projects. TW elements can be imported in Vite applications according to the following procedure:
1. Create a new vite project and enter the newly created directory. Pick
Vanilla
framework and JavaScript
variant. You can
skip this step if you already have it installed.
npm create vite@latest my-project
cd my-project
2. Install tailwind CSS and its dependencies. After that,
init
the tailwind with the Tailwind CLI tool to create
tailwind.config.js
file.
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
3. Go to the tailwind.config.js
file and add paths where your
html files are going to be stored. You can change the
index.html
location but make sure to change to
root folder
inside the vite.config.js
file.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
4. Add the necessary Tailwind directives to your style.css
file
to be able to use Tailwind classes on your website. Unless you changed it,
style.css
should be in the root directory of your app. You can
also remove the default content of the style.css
file if you
want.
@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap");
@tailwind base;
@layer base {
html {
@apply text-surface;
@apply bg-white;
}
html.dark {
@apply text-neutral-50;
@apply bg-body-dark;
}
}
@tailwind components;
@tailwind utilities;
p {
@apply leading-[1.6];
}
5. Link the css file inside the index.html
.
<head>
...
<link rel="stylesheet" href="style.css" />
...
</head>
6. Tailwind should be connected properly to the vite app. If you type the
code bellow, you will see the default vite index.html
page
(without any styles if you deleted them from style.css
).
npm run dev
7. Install the tw-elements
package.
npm install tw-elements
8. Add js files patterns that loads dynamic component classes to the content
array inside the tailwind.config.js
. Extend the default
tailwind classes by adding the TW elements
plugin.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{html,js}",
"./node_modules/tw-elements/js/**/*.js",
],
plugins: [require("tw-elements/plugin.cjs")],
darkMode: "class"
};
9. Now you can start working on your app. Since the package.json created by
vite has a type set to module
, we are going to use the
ES
. Lets try to import some code and see if everything is
working correctly. Don't forget to call the initTWE
method. The
carousel component should have proper styles, and change the current image
after arrow click or after some delay.
initTWE({ Carousel, Tooltip, Input });
<body class="dark:bg-neutral-800">
<div
id="carouselExampleCaptions"
class="relative"
data-twe-carousel-init
data-twe-carousel-slide>
<div
class="absolute bottom-0 left-0 right-0 z-[2] mx-[15%] mb-4 flex list-none justify-center p-0"
data-twe-carousel-indicators>
<button
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide-to="0"
data-twe-carousel-active
class="mx-[3px] box-content h-[3px] w-[30px] flex-initial cursor-pointer border-0 border-y-[10px] border-solid border-transparent bg-white bg-clip-padding p-0 -indent-[999px] opacity-50 transition-opacity duration-[600ms] ease-[cubic-bezier(0.25,0.1,0.25,1.0)] motion-reduce:transition-none"
aria-current="true"
aria-label="Slide 1"></button>
<button
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide-to="1"
class="mx-[3px] box-content h-[3px] w-[30px] flex-initial cursor-pointer border-0 border-y-[10px] border-solid border-transparent bg-white bg-clip-padding p-0 -indent-[999px] opacity-50 transition-opacity duration-[600ms] ease-[cubic-bezier(0.25,0.1,0.25,1.0)] motion-reduce:transition-none"
aria-label="Slide 2"></button>
<button
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide-to="2"
class="mx-[3px] box-content h-[3px] w-[30px] flex-initial cursor-pointer border-0 border-y-[10px] border-solid border-transparent bg-white bg-clip-padding p-0 -indent-[999px] opacity-50 transition-opacity duration-[600ms] ease-[cubic-bezier(0.25,0.1,0.25,1.0)] motion-reduce:transition-none"
aria-label="Slide 3"></button>
</div>
<div
class="relative w-full overflow-hidden after:clear-both after:block after:content-['']">
<div
class="relative float-left -me-[100%] w-full transition-transform duration-[600ms] ease-in-out motion-reduce:transition-none"
data-twe-carousel-active
data-twe-carousel-item
style="backface-visibility: hidden">
<img
src="https://tecdn.b-cdn.net/img/Photos/Slides/img%20(15).jpg"
class="block w-full"
alt="..." />
<div
class="absolute inset-x-[15%] bottom-5 hidden py-5 text-center text-white md:block">
<h5 class="text-xl">First slide label</h5>
<p>
Some representative placeholder content for the first slide.
</p>
</div>
</div>
<div
class="relative float-left -me-[100%] hidden w-full transition-transform duration-[600ms] ease-in-out motion-reduce:transition-none"
data-twe-carousel-item
style="backface-visibility: hidden">
<img
src="https://tecdn.b-cdn.net/img/Photos/Slides/img%20(22).jpg"
class="block w-full"
alt="..." />
<div
class="absolute inset-x-[15%] bottom-5 hidden py-5 text-center text-white md:block">
<h5 class="text-xl">Second slide label</h5>
<p>
Some representative placeholder content for the second slide.
</p>
</div>
</div>
<div
class="relative float-left -me-[100%] hidden w-full transition-transform duration-[600ms] ease-in-out motion-reduce:transition-none"
data-twe-carousel-item
style="backface-visibility: hidden">
<img
src="https://tecdn.b-cdn.net/img/Photos/Slides/img%20(23).jpg"
class="block w-full"
alt="..." />
<div
class="absolute inset-x-[15%] bottom-5 hidden py-5 text-center text-white md:block">
<h5 class="text-xl">Third slide label</h5>
<p>
Some representative placeholder content for the third slide.
</p>
</div>
</div>
</div>
<button
class="absolute bottom-0 left-0 top-0 z-[1] flex w-[15%] items-center justify-center border-0 bg-none p-0 text-center text-white opacity-50 transition-opacity duration-150 ease-[cubic-bezier(0.25,0.1,0.25,1.0)] hover:text-white hover:no-underline hover:opacity-90 hover:outline-none focus:text-white focus:no-underline focus:opacity-90 focus:outline-none motion-reduce:transition-none"
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide="prev">
<span class="inline-block h-8 w-8">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-6 w-6">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
</span>
<span
class="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]"
>Previous</span
>
</button>
<button
class="absolute bottom-0 right-0 top-0 z-[1] flex w-[15%] items-center justify-center border-0 bg-none p-0 text-center text-white opacity-50 transition-opacity duration-150 ease-[cubic-bezier(0.25,0.1,0.25,1.0)] hover:text-white hover:no-underline hover:opacity-90 hover:outline-none focus:text-white focus:no-underline focus:opacity-90 focus:outline-none motion-reduce:transition-none"
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide="next">
<span class="inline-block h-8 w-8">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-6 w-6">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</span>
<span
class="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]"
>Next</span
>
</button>
</div>
<script type="module" src="/main.js"></script>
</body>
import { Carousel, initTWE } from "tw-elements";
initTWE({ Carousel } );
Vite with Bun
Bun is a tool that is designed to replace Node.js in the development of web applications. The main goal of Bun is to reduce the startup times and memory usage of created apps. Vite works with Bun out of the box. TW Elements can be imported in Vite applications according to the following procedure:
1. Make sure to have the Bun installed. You can run the following command to check whether Bun is working properly:
bun --version
If the console is showing the version of Bun it means that the installation was successful and you can proceed to the next step.
2. Create a new vite project and enter the newly created directory. Pick
Vanilla
framework and JavaScript
variant.
bun create vite my-project
cd my-project
bun install
3. Install tailwind CSS and its dependencies. After that,
init
the tailwind with the Tailwind CLI tool to create
tailwind.config.js
file.
bun install -D tailwindcss postcss autoprefixer
bunx tailwindcss init -p
4. Add the Tailwind directives to your style.css
file to be
able to use Tailwind classes on your website.
@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap");
@tailwind base;
@layer base {
html {
@apply text-neutral-800;
}
html.dark {
@apply text-neutral-50;
@apply bg-neutral-800;
}
}
@tailwind components;
@tailwind utilities;
5. Link the css file inside the output.html
. We are linking the
output.html
file instead of the style.css
because
thats where the tailwindcss CLI is going to add the styling classes.
<head>
...
<link rel="stylesheet" href="output.css" />
...
</head>
6. Install the tw-elements
package.
bun install tw-elements
7. Add js files patterns that loads dynamic component classes to the content
array inside the tailwind.config.js
. Extend the default
tailwind classes by adding the TW elements
plugin.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{html,js}",
"./node_modules/tw-elements/js/**/*.js",
],
plugins: [require("tw-elements/plugin.cjs")],
darkMode: "class"
};
8. Build the output.css
file with use of the tailwindcss CLI.
You can also add this command to the package.json
file to make
it easier to use.
bunx tailwindcss -i ./style.css -o ./output.css --watch
9. Now you can start working on your app. Copy the code bellow to add a
carousel component to your app. Don't forget to call the
initTWE
method.
<body class="dark:bg-neutral-800">
<div
id="carouselExampleCaptions"
class="relative"
data-twe-carousel-init
data-twe-carousel-slide>
<div
class="absolute bottom-0 left-0 right-0 z-[2] mx-[15%] mb-4 flex list-none justify-center p-0"
data-twe-carousel-indicators>
<button
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide-to="0"
data-twe-carousel-active
class="mx-[3px] box-content h-[3px] w-[30px] flex-initial cursor-pointer border-0 border-y-[10px] border-solid border-transparent bg-white bg-clip-padding p-0 -indent-[999px] opacity-50 transition-opacity duration-[600ms] ease-[cubic-bezier(0.25,0.1,0.25,1.0)] motion-reduce:transition-none"
aria-current="true"
aria-label="Slide 1"></button>
<button
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide-to="1"
class="mx-[3px] box-content h-[3px] w-[30px] flex-initial cursor-pointer border-0 border-y-[10px] border-solid border-transparent bg-white bg-clip-padding p-0 -indent-[999px] opacity-50 transition-opacity duration-[600ms] ease-[cubic-bezier(0.25,0.1,0.25,1.0)] motion-reduce:transition-none"
aria-label="Slide 2"></button>
<button
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide-to="2"
class="mx-[3px] box-content h-[3px] w-[30px] flex-initial cursor-pointer border-0 border-y-[10px] border-solid border-transparent bg-white bg-clip-padding p-0 -indent-[999px] opacity-50 transition-opacity duration-[600ms] ease-[cubic-bezier(0.25,0.1,0.25,1.0)] motion-reduce:transition-none"
aria-label="Slide 3"></button>
</div>
<div
class="relative w-full overflow-hidden after:clear-both after:block after:content-['']">
<div
class="relative float-left -me-[100%] w-full transition-transform duration-[600ms] ease-in-out motion-reduce:transition-none"
data-twe-carousel-active
data-twe-carousel-item
style="backface-visibility: hidden">
<img
src="https://tecdn.b-cdn.net/img/Photos/Slides/img%20(15).jpg"
class="block w-full"
alt="..." />
<div
class="absolute inset-x-[15%] bottom-5 hidden py-5 text-center text-white md:block">
<h5 class="text-xl">First slide label</h5>
<p>
Some representative placeholder content for the first slide.
</p>
</div>
</div>
<div
class="relative float-left -me-[100%] hidden w-full transition-transform duration-[600ms] ease-in-out motion-reduce:transition-none"
data-twe-carousel-item
style="backface-visibility: hidden">
<img
src="https://tecdn.b-cdn.net/img/Photos/Slides/img%20(22).jpg"
class="block w-full"
alt="..." />
<div
class="absolute inset-x-[15%] bottom-5 hidden py-5 text-center text-white md:block">
<h5 class="text-xl">Second slide label</h5>
<p>
Some representative placeholder content for the second slide.
</p>
</div>
</div>
<div
class="relative float-left -me-[100%] hidden w-full transition-transform duration-[600ms] ease-in-out motion-reduce:transition-none"
data-twe-carousel-item
style="backface-visibility: hidden">
<img
src="https://tecdn.b-cdn.net/img/Photos/Slides/img%20(23).jpg"
class="block w-full"
alt="..." />
<div
class="absolute inset-x-[15%] bottom-5 hidden py-5 text-center text-white md:block">
<h5 class="text-xl">Third slide label</h5>
<p>
Some representative placeholder content for the third slide.
</p>
</div>
</div>
</div>
<button
class="absolute bottom-0 left-0 top-0 z-[1] flex w-[15%] items-center justify-center border-0 bg-none p-0 text-center text-white opacity-50 transition-opacity duration-150 ease-[cubic-bezier(0.25,0.1,0.25,1.0)] hover:text-white hover:no-underline hover:opacity-90 hover:outline-none focus:text-white focus:no-underline focus:opacity-90 focus:outline-none motion-reduce:transition-none"
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide="prev">
<span class="inline-block h-8 w-8">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-6 w-6">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
</span>
<span
class="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]"
>Previous</span
>
</button>
<button
class="absolute bottom-0 right-0 top-0 z-[1] flex w-[15%] items-center justify-center border-0 bg-none p-0 text-center text-white opacity-50 transition-opacity duration-150 ease-[cubic-bezier(0.25,0.1,0.25,1.0)] hover:text-white hover:no-underline hover:opacity-90 hover:outline-none focus:text-white focus:no-underline focus:opacity-90 focus:outline-none motion-reduce:transition-none"
type="button"
data-twe-target="#carouselExampleCaptions"
data-twe-slide="next">
<span class="inline-block h-8 w-8">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-6 w-6">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</span>
<span
class="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]"
>Next</span
>
</button>
</div>
<script type="module" src="/main.js"></script>
</body>
import { Carousel, initTWE } from "tw-elements";
initTWE({ Carousel } );
10. Update the scripts inside the package.json
file so that the
development server can be started using bunx
instead of
node
. You can do the same with the build
script.
"scripts": {
"dev": "bunx --bun vite",
"build": "bunx --bun vite build",
},
11. Tailwind should be connected properly to the vite app with Bun.
bun run dev
<link
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap"
rel="stylesheet" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/tw-elements/css/tw-elements.min.css" />
<script src="https://cdn.tailwindcss.com/3.3.0"></script>
<script>
tailwind.config = {
darkMode: "class",
theme: {
fontFamily: {
sans: ["Roboto", "sans-serif"],
body: ["Roboto", "sans-serif"],
mono: ["ui-monospace", "monospace"],
},
},
corePlugins: {
preflight: false,
},
};
</script>
dist/
folder in the source path to our TW Elements package.
Make sure to use the new path in CDN links.
Require the js bundled file right before the body
closing tag.
Use the UMD
file if used without a bundler.
<script src="https://cdn.jsdelivr.net/npm/tw-elements/js/tw-elements.umd.min.js"></script>