Prerequisites
Before starting the project make sure to install the following utilities:
- Node LTS (18.x.x or higher recommended)
- Angular (14.x.x or higher recommended)
- Code editor. We recommendVSCode
Angular TW elements:
Currently we are working on a standalone Angular version of TW Elements. If you want to know when it is going to be released, sign in in ourwaiting list available here.
Creating a new Angular application
Let's create a fresh Angular application so that we can go through all the steps together.
Step 1
Install Angular CLI
npm install -g @angular/cli
Step 2
Create new project
ng new my-project cd my-project
CSS
when prompted.Installing and configuring Tailwind CSS and TW Elements
Step 1
Install Tailwind CSS.
npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
File structure
If you have followed all instructions mentioned earlier, your file structure should look like this:
my-project/ ├── node_modules/ ├── src/ │ ├── app/ │ │ ├── app.component.html │ │ ├── app.component.ts │ │ └── ... │ ├── assets/ │ | └── ... │ ├── index.html │ ├── main.ts │ └── styles.css ├── angular.json ├── package-lock.json ├── package.json ├── postcss.config.js ├── tailwind.config.js ├── ... └── tsconfig.spec.json
Step 2
Add the paths to all of your template files in yourtailwind.config.js
file.
/** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./src/**/*.{html,ts}", "./node_modules/tw-elements/js/**/*.js" ], theme: { extend: {}, }, darkMode: "class", plugins: [require("tw-elements/plugin.cjs")] }
Step 3
Add the@tailwind
directives for each of Tailwind’s layers to yourstyles.css
file.
@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]; }
Step 4
Install TW Elements.
npm install tw-elements
Step 5
Import components which are you intend to use and necessary functioninitTWE
. InitializeinitTWE
in a lifecycle method.
import { Component } from '@angular/core'; import { Tooltip, initTWE } from 'tw-elements'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { ngOnInit() { initTWE({ Tooltip }); } }
<div class="mt-16 flex justify-center"> <p class="text-lg"> Hover the link to see the <a href="#" class="text-primary transition duration-150 ease-in-out hover:text-primary-600 focus:text-primary-600 active:text-primary-700 dark:text-primary-400 dark:hover:text-primary-500 dark:focus:text-primary-500 dark:active:text-primary-600" data-twe-toggle="tooltip" title="Hi! I'm tooltip" >tooltip</a > </p> </div>
Step 6
Start the app and see if everything's fine. Awesome! You're all set to dive into using TW Elements for your Angular project. Have fun!
ng serve --open
Initializing via JS
By default all components have autoinit which means they are initialized by data attributes. But if you want to make init by JavaScript - there is also possibility to do that.
Step 1
Import components which are you intend to use and initialize components in lifecycle hook.
import { Component } from '@angular/core'; import { Tooltip } from 'tw-elements'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { ngOnInit() { const myTooltip = new Tooltip(document.getElementById('my-tooltip')); } }
<div class="mt-16 flex justify-center"> <p class="text-lg"> Hover the link to see the <a id="my-tooltip" href="#" class="text-primary transition duration-150 ease-in-out hover:text-primary-600 focus:text-primary-600 active:text-primary-700 dark:text-primary-400 dark:hover:text-primary-500 dark:focus:text-primary-500 dark:active:text-primary-600" title="Hi! I'm tooltip" >tooltip</a > </p> </div>
Troubleshooting
Problem overview:
Implementing theRipple
class with the ES init method for button ripple effects poses a challenge. When usinginitTWE({Ripple})
in the same component folder where the button is used, it works fine. However, the user wants to avoid using this initialization for every component individually. Attempts to export a shared button component and import it into the root module did not resolve the issue. The ES init method seems not to reach the desired component or the shared button component.
Suggested solution:
A practical solution involves creating a dedicatedte-initiator.component
responsible for theinitTWE({ Ripple })
call without theallowReinits
option, preventing multiple initiations. This approach involves extending thete-initiator.component
to every child component needing the ES init.
export class TEInitiatorComponent implements OnInit { constructor() { } ngOnInit() { initTWE({ Ripple }); } }
export class ButtonOutlineComponent extends TEInitiatorComponent { constructor() {} }
Source GitHub Discussion #2014
Problem overview:
Users may encounter initialization issues with TWE components when navigating through applications with routing mechanisms. The default behavior of theinitTWE
method includes checking if components are already initialized, which can lead to complications when components are unmounted and then remounted during routing.
Suggested solution:
Consider using usingautoReinits
option ininitTWE
method. By default it's value is set tofalse
. By changing the value totrue
, theinitTWE
method won't check if components were already initialized.
initTWE({ Tooltip }, { allowReinits: true });
Source TW Elements Team
Problem overview:
The user is encountering difficulties while dynamically creating accordion items in Angular 13+ using*ngFor
. The objective is to implement a customizable Angular component that leverages TW Elements Accordion. Despite successfully rendering accordion children with*ngFor
, the collapse functionality doesn't work. This issue is comparable with a previous difficulty associated with Efficient Initialization withinitTWE()
Method.
Suggested solution:
A practical solution involves strategically placinginitTWE()
in various lifecycles, includingOnInit
,AfterViewInit
, andAfterViewChecked
, with the exception ofOnChanges
. This multi-lifecycle coverage ensures thatinitTWE()
is triggered at different stages of the component lifecycle.
export class TeInitiatorComponent implements OnInit, AfterViewInit, AfterViewChecked { constructor() { } ngOnInit() { initTWE({ Collapse }); } ngAfterViewInit() { initTWE({ Collapse }); } ngAfterViewChecked() { initTWE({ Collapse }); } }
Source GitHub Discussion #2060
Problem overview:
A specific challenge arises with an Angular website, utilizing TWE Carousel to showcase project images on the homepage. While the carousels function correctly withng serve
, unexpected behavior occurs when using prerender to build and serve the website. Problems include image transition glitches, such as abrupt switches or images overlapping.
Suggested solution:
Consider investigating methods to selectively skip component rendering during prerendering, allowing the component to load normally. Another approach involves utilizing Angular'sisPlatformServer
method within theshouldRenderComponent
method, providing an opportunity to conditionally control component rendering during prerendering.