If you use Tailwind, you may have also encountered DaisyUI and its library of web components built on top of Tailwind.
Maybe, like me, you didn’t realize at first that Daisy has no JS - all its effects are pure CSS.
But there are times when you need some extra help to make the best use of some Daisy components.
Here is one basic example: the tabs component - specifically, in this example, Daisy’s boxed tabs.
Out of the box (no pun intended), if you use the following sample code…
|
|
…then you get a nice row of tab buttons which don’t do anything. They are completely inert. And they stretch across the entire width of the web page:
It’s not a great amount of effort to add some JavaScript to this, to breathe life into these tabs, but I wanted to try out Alpine.js to see if that could minimize the amount of code I needed to write.
My first attempt was this:
|
|
This creates three left-justified tab buttons, each of which can open a related content panel:
How does this work?
The Tailwind class justify-start
positions the tabs on the left hand side of the tabs bar.
The following Alpine directives are used (in my case I added a CDN <script>
to my web page for Alpine):
x-data
which contains a JavaScript object { foo: true, bar: false, baz: false }
. The object is used to control which tab is selected and visible (true
). All the other tabs are closed (false
). This data is available to all descendant directives.x-on:click
- but here I use the shorthand syntax @click
. For each tab, there is a click
event which resets the x-data
object’s values as needed.x-bind:class
- but here I use another shorthand: :class
. This references a JavaScript expression, which adds the Daisy class tab-active
to the element (or removes it), depending on how the JavaScript expression is evaluated - for example, foo && 'tab-active'
.x-show
which controls which of the tab panels is displayed (the one where the x-data
is true
).That is everything needed to create a functioning set of Daisy tabs.
One additional clarification: The JavaScript foo && 'tab-active'
may be less familiar to some people (it was to me). These are equivalent expressions here:
`foo ? 'tab-active' : ''`
`foo && 'tab-active'`
My first attempt works well, but it involves a lot of repetitious settings of true
and false
values.
This next attempt tries to improve the situation - at least somewhat…
|
|
And now we also have some separate JavaScript, in a <script>
tag:
|
|
The heart of this approach is the Alpine.data(...)
global function, which is registered as an event listener when Alpine is first initialized.
Here mytabs
is a JavaScript function, which is referenced in the HTML <div x-data="mytabs">
. This means I have basically moved the previous x-data="{...}"
settings from their old HTML location into JavaScript.
As well as this x-data
, there is also another function reveal(selected_tab)
which is called by each @click
event. This function resets all tabs to false
(not visible) and then finally sets the clicked tab to true
(visible).
Note how the code uses this.foo
and so on to refer to each data item.
The end result is somewhat less cluttered HTML. I think it is an improvement.
One advantage of the updated approach is that is makes further customizations incrementally easier.
The following modifications allow the tabs page to be opened to any specific tab by appending ?tab=whatever
to the end of the page URL as a query string. Now, the whatever
tab will be opened by default.
The code also modifies the URL’s query string dynamically, as different tabs are opened - which means you can bookmark specific tabs in the web page.
You can read more about URLSearchParams
.
|
|
Not exactly relevant to the above notes, but just for fun… I discovered Tailwind, Daisy and Alpine when I was investigating Next.js.
Along the way I encountered a plethora of tools and libraries which I had never or rarely used before…
React | Notes |
---|---|
Node.js | JavaScript runtime. JavaScript outside the browser. |
React | Front-end JS library. Focus is on the user interface by building “components”; and rendering to the DOM via a “virtual DOM”. |
Next.js | A React framework for web sites. Supports server-side rendering for some/all components; routing, etc. for a full framework. |
TypeScript | JavaScript, but strongly-typed. Transpiles to plain JS. |
JSX | A React syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file. See also the spec. Transpiles to plain JS, with the HTML parts transpiled to the relevant React calls, such as React.createElement . |
TSX | A syntax extension for TypeScript files to support JSX. |
Prisma | A database toolkit. It includes a JavaScript/TypeScript ORM for Node.js. |
CSS Things | Notes |
---|---|
Tailwind CSS | CSS framework using utility classes. But can get verbose. See daisyUI. |
CSS Modules | A CSS Module is a CSS file where all class names and animation names are scoped locally by default. |
Sass | CSS extension language (nesting, mixins, inheritance, etc). |
daisyUI | Adds component class names to Tailwind CSS - makes it less verbose. |
Chakra UI | CSS component library for use in React applications. |
Foundation Framework | SASS/CSS framework for web UI components. |
Tools | Notes |
---|---|
Prettier | Code formatter for JS, CSS, HTML, Markdown, and more. |
Gulp | Build/automation tool on Node.js. |
Vite | Build/automation tool; built-in dev server. |
Grunt | Build/automation tool using JavaScript. |
Yarn | JavaScript package manager. |
npm | JavaScript package manager. |
pnpm | JavaScript package manager. |
Babel | A JavaScript compiler mainly used to convert ECMAScript 2015+ code into backwards compatible versions of JavaScript to match what browsers may support. |
Webpack | JavaScript module bundler. Takes modules with dependencies and generates static assets representing those modules. |
Also… | Notes |
---|---|
Angular | TypeScript-based single-page web application framework for Node.js. |
Vue | Front end JavaScript framework for building user interfaces and single-page applications. |
Express | Back end web application framework for building RESTful APIs with Node.js. |
And the above list is really just scratching the surface of an enormous ecosystem, with no hint of Java anywhere.