Install

Getting started

Install

Import jellyfy.css for every control, or import the component files you use. startJellyfy() runs the press and the loading lights, and it keeps the range fill in step with the input.

Install the package

npm install jellyfy

The whole library

One file. It imports the material, the motion, and every component. Put it after Tailwind. A utility such as px-4 still sets that padding. The press stays.

@import "tailwindcss";
@import "jellyfy/jellyfy.css";

Without Tailwind, link that file or import it from a bundler.

<link rel="stylesheet" href="./node_modules/jellyfy/jellyfy.css" />
import "jellyfy/jellyfy.css";

One component

Import the material, the motion, and the components you use. A component file that is not imported is not in the build. Do not also import jellyfy.css. That file already contains these.

@import "tailwindcss";
@import "jellyfy/material.css";
@import "jellyfy/motion.css";
@import "jellyfy/button.css";
@import "jellyfy/input.css";

Without Tailwind, drop the Tailwind line. The same files work from a link tag or a bundler.

  • material.css is required. It holds the grain, the blur, and the colors.
  • motion.css is required. It holds the press.
  • button.css is btn.
  • icon-button.css is btn-icon.
  • bump-button.css is btn-bump.
  • input.css, textarea.css, select.css, checkbox.css, radio.css, toggle.css, range.css, alert.css, badge.css, card.css, modal.css, and message.css match those class names. The switch is toggle.css. The range slider is range.css. The dialog is modal.css.

Call it once

Call startJellyfy() once, after the controls are on the page. A pointer press squashes the control under the pointer. Controls that appear later, including after a page change, are included. A later call is ignored. The full pages are in examples.

Plain HTML

<script type="module">
  import { startJellyfy } from "./node_modules/jellyfy/index.js";

  startJellyfy();
</script>

Vue

Import the CSS in the entry. Use jellyfy/jellyfy.css for the whole library, or the material, the motion, and the component files. Call the function when the app is mounted.

import { createApp } from "vue";

import App from "./App.vue";
import "jellyfy/jellyfy.css";

createApp(App).mount("#app");
<script setup>
import { startJellyfy } from "jellyfy";
import { onMounted } from "vue";

onMounted(() => {
  startJellyfy();
});
</script>

React

Import the CSS after Tailwind. Use jellyfy/jellyfy.css, or the component files. Call the function once from the root component.

import "jellyfy/jellyfy.css";
import { startJellyfy } from "jellyfy";
import { useEffect } from "react";

export default function App() {
  useEffect(() => {
    startJellyfy();
  }, []);
}

Press any element

Add squish to give any element the same press. On a Jellyfy control it uses the face that control already has. Add it to a card when the card should press. A disabled control does not squish.

<article class="card squish">Notes</article>

Your own element

The thickness classes paint the jelly on an element that is not a Jellyfy component. They need the material file, which the whole library already includes.

<div class="thickness-surface">A surface</div>
<div class="thickness-field">A field</div>
<div class="thickness-control">A control</div>
<div class="thickness-mark">A mark</div>

Add noise for the grain alone. Put it on your own element the way you put squish on it for the press, or a thickness class on it for the edge.

<div class="noise">Grain only</div>

Browser support

Chrome and Edge 123+, Firefox 120+, and Safari / iOS Safari 17.5+. Jellyfy uses native light-dark() for theme-aware colors and material lighting.