Welcome To Mini

Mini lets you add interactivity to your web apps without leaving your HTML.

Mini is currently in Alpha. While we don't anticipate any major API changes, there are several known issues, including a relatively large file size (80kb gzipped). We're actively working on improvements and don't expect to release a beta version until 2025.

Getting Started

To add Mini to your project, simply save this file to your codebase and load it when your page loads.

<script src="/mini.js" ></script>

Alternatively you can also load Mini directly from our CDN if you prefer.

<script src="https://cdn.mini-js.com/1.0.15.js" ></script>

What can Mini do?

Mini is an extremely easy to use way to add UI Behaviour to your web software. It's not designed to store all of your state — for example it doesn't include routing or authentication — so it works best when paired with a Server-side Rendered approach.

The best way to understand where Mini shines is to see some examples.

Add classes to elements when clicked

  • Simple Dropdown Menu: "When a user clicks the button, add some classes to the arrow icon, and the hidden div that holds the menu."
<button :click="showMenu = !showMenu" :clickout="showMenu = false">
  <div :class="showMenu ? 'rotate-180' : '' " ></div>
  Show Menu
</button>
<div :class="showMenu ? 'transform opacity-100 scale-100' : 'transform opacity-0 scale-95 pointer-events-none' "></div>
  • Simple Flight Picker: "When a user clicks the button, add some classes to the hidden flight picker div, and remove them from other divs."
Adults
> 11 years
-
+
Children
2 to 11 years
-
+
Babies
2 years
-
+
Save

Learn Mini (in Three Steps)


1. Prefix your html attributes with : to let them evaluate javascript

For example, for form inputs, use :value to set an input's value.

<input type="text" :value="window.navigator.userAgent" />

This will display this ⤵

  • To set an element's class, use the :class attribute
  • To set an element's style, use the :style attribute
  • And so on...

2. Use vanilla javascript variables to store state

Variables default to the global namespace, so you can define your data anywhere in your page and use it later.

<script>
  firstName="Michael"
  lastName="Scott"
</script>
<input type="text" :value="firstName + ` ` +lastName" />

This will display this ⤵


3. Use events to respond to user interactions.

Mini extends the browser's native events with shorthand attributes like :click, :change, :press, :clickout and a few others. For example, you can use the:click attribute to respond to elements being clicked

<script>
  firstName="Michael"
  lastName="Scott"
</script>
<button :click="firstName = 'Pamela'" />
<button :click="lastName = 'Halpert'" />
<input type="text" :value="firstName + ` ` +lastName"  />

Combine these patterns 👆 for infinite possibilities

Being able to set state using javascript variables, update state in response to interactions, and mutate the dom depending on the state, unlocks a lot of UI patterns.


More Mini

Now that you've learned the basics, here are a few more tricks you can use.

Use :text to set the inner text of an element

<span :text="`My lucky number is: `+Math.floor(Math.random() * 100) + 1;" />

This will display:

Use :change to monitor form inputs, and this.value to get their values

<input type="text" :change="firstName=this.value" />
<span :text="`Your first name is: ` + firstName">
Your first name is:


Use event to get the current event

You can also access the current event with the event keyword.

<button :click="console.log(event)">Click Me</button>


Use :each to loop through arrays or objects

While we don't recommend storing deep state, we do provide the ability to iterate through and display collections of objects, like so.

<script>
  todos = [
    { name: "Clean Dishes",  complete: true },
    { name: "Vacuum Floors", complete: false}
  ]
</script>
<div :each="todo in todos">
  <div :text="todo.name"></div>
</div>

Use :load to execute code when an element is loaded

Sometimes we want code to be executed as soon as the page, or a specific element on the page, is loaded.

<div :load="console.log('I was loaded')"></div>

This is also useful when looping through arrays with :each.


Scoping

We often need to group together elements which draw from the same state. To do this, first we add the :scope attribute to the outer HTML element, then we prefix our variables with scope..

<div :scope>
  <button :click="scope.showDropdown = true">First Dropdown</button>
  <div :class="scope.showDropdown ? 'block' : 'hidden'"></div>
</div>
<div :scope>
  <button :click="scope.showDropdown = true">Second Dropdown</button>
  <div :class="scope.showDropdown ? 'block' : 'hidden'"></div>
</div>

We can also set the default values within a scoped group when they load.

<div :scope="showDropdown=true">
  <button :click="scope.showDropdown = true">First Dropdown</button>
  <div :class="scope.showDropdown ? 'block' : 'hidden'"></div>
</div>

Use el. to scope state to a specific dom element

The benefit of scope is that you can have groups of dom elements that all share state. But sometimes your state only needs to exist on a single element. In this case you can use the el. prefix before your variables.

<div
  :load="el.bgColor=bg-green-900"
  :class="el.bgColor">
</div>

It's Just Javascript

The basic premise of Mini is to let attributes execute javascript. This means you can do anything javascript can do, including, for example:

Basic, If Else statements

<div
  :class="if (selectedTab === 'when') {
            'bg-white shadow-lg'
          } else {
            'hover:bg-gray-300'
          }"
></div>

Nested Ternaries

<div
  :class="(selectedTab === 'When' ? 'bg-white shadow-lg' : 'hover:bg-gray-300')
          (whenSelectedTab === 'Dates' ? 'hidden' : '')"
></div>

Helpers

Because javascript is quite verbose, putting it inside of our attributes can get unwieldy quickly. So we added some helper methods that make doing common things like setting timeouts and working with arrays, a little more tidy.

Use await wait() instead of setTimeout()

<button :click="alert('Starting');await wait(3000);alert('Ended')">
</button>

Use Array helpers to filter and manipulate data

<script>
  fruits=['Apple','Banana','Pear','Strawberry','Grape','Pineapple']
  filteredFruits = fruits
</script>
<input type="text" :change="filteredFruits = fruits.search(this.value);">
<div :each="fruit in filteredFruits">
  <div :text="fruit"></div>
</div>
Results

See all the custom methods in the Reference here.


Keyboard Events

For keyboard events, you can listen to them using :keyup, :keydown, and :keypress:

<input type="text" :keyup="console.log(event)" />

You can also do cool stuff like chaining keyboard modifiers together. See The Reference for more info.