View Source LiveViewUI

Add free, easy-to-customize components to your LiveView apps. Start building your LiveView component library today!

⚠️ WARNING: This package is still in early development. Please do not use it for production or active projects. Contributions are welcome to help make it more stable!

Installation

Prerequisites

Make sure you have tailwindcss installed in your project.

Step 1: Add the Dependency

Open your Phoenix project and add live_view_ui to your list of dependencies in mix.exs:

def deps do
  [
    {:live_view_ui, "~> 0.0.1"}, # <-- Add this line
  ]
end

Run mix deps.get to fetch and install the dependencies.

Step 2: Configure TailwindCSS

Update your tailwind.config.js to include the UI library's components and themes:

module.exports = {
  content: [
    "../lib/ui/**/*.ex", // <-- Add this line
  ],
  darkMode: "class", // <-- Add this line
  theme: {
    extend: {
      colors: {
        ...require("../deps/live_view_ui/assets/tailwind.colors.json"), // <-- Add this line
      },
    },
  },
  plugins: [
    require("../deps/live_view_ui/assets/preline/plugin"), // <-- Add this line
  ],
};

Step 3: Update app.css

Add the following styles to your app.css to integrate the library's base styles:

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 240 10% 3.9%;
    --card: 0 0% 100%;
    --card-foreground: 240 10% 3.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 240 10% 3.9%;
    --primary: 240 5.9% 10%;
    --primary-foreground: 0 0% 98%;
    --secondary: 240 4.8% 95.9%;
    --secondary-foreground: 240 5.9% 10%;
    --muted: 240 4.8% 95.9%;
    --muted-foreground: 240 3.8% 46.1%;
    --accent: 240 4.8% 95.9%;
    --accent-foreground: 240 5.9% 10%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 0 0% 98%;
    --border: 240 5.9% 90%;
    --input: 240 5.9% 90%;
    --ring: 240 5.9% 10%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 240 10% 3.9%;
    --foreground: 0 0% 98%;
    --card: 240 10% 3.9%;
    --card-foreground: 0 0% 98%;
    --popover: 240 10% 3.9%;
    --popover-foreground: 0 0% 98%;
    --primary: 0 0% 98%;
    --primary-foreground: 240 5.9% 10%;
    --secondary: 240 3.7% 15.9%;
    --secondary-foreground: 0 0% 98%;
    --muted: 240 3.7% 15.9%;
    --muted-foreground: 240 5% 64.9%;
    --accent: 240 3.7% 15.9%;
    --accent-foreground: 0 0% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 0 0% 98%;
    --border: 240 3.7% 15.9%;
    --input: 240 3.7% 15.9%;
    --ring: 240 4.9% 83.9%;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply text-foreground bg-background;
  }
}

@keyframes slide-in {
  from {
    height: 0px;
  }
  to {
    height: var(--sprt-collapsible-content-height);
  }
}

@keyframes slide-out {
  from {
    height: var(--sprt-collapsible-content-height);
  }
  to {
    height: 0px;
  }
}

.animate-slide-down {
  animation: slide-down 200ms cubic-bezier(0.87, 0, 0.13, 1);
}

.animate-slide-up {
  animation: slide-up 200ms cubic-bezier(0.87, 0, 0.13, 1);
}

@keyframes slide-down {
  from {
    height: 0;
  }
  to {
    height: var(--panel-height);
  }
}

@keyframes slide-up {
  from {
    height: var(--panel-height);
  }
  to {
    height: 0;
  }
}

select {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
  background-position: right 0.5rem center;
  background-repeat: no-repeat;
  background-size: 1.5em 1.5em;
  padding-right: 2.5rem;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;

  /* reset */

  margin: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  -webkit-appearance: none;
  -moz-appearance: none;
}

::-webkit-scrollbar {
  @apply w-2 h-2;
}

::-webkit-scrollbar-track {
  @apply bg-background;
}

::-webkit-scrollbar-thumb {
  @apply rounded-full bg-zinc-700;
}

::-webkit-scrollbar-thumb:hover {
  @apply bg-zinc-800;
}

.thin-scrollbar::-webkit-scrollbar {
  @apply w-1.5 h-1.5;
}

.thin-scrollbar::-webkit-scrollbar-track {
  @apply bg-background;
}

Refer to the shadcn/ui Themes to customize the colors to your liking.

Step 4: Modify app.js

Ensure that your app.js is configured to utilize LiveView hooks and DOM operations from the UI library:

import { hooks, dom } from "../../deps/live_view_ui/assets/app"; // <-- Add this line

const liveSocket = new LiveSocket("/live", Socket, {
  hooks, // <-- Add this line
  dom, // <-- Add this line
});

Step 5: Copy the UI Components

  1. Copy the UI Components: To use the UI components provided by the library, you need to copy them into your project directory. Run the following command in your terminal:

    cp -R ./deps/live_view_ui/lib/ui ./lib
    
  2. Change the Gettext module in ./lib/ui/input.ex to match your project's Gettext module.

Step 6: For dark mode support

If you want to support dark mode, you need to add the following code to your root.html.heex:

<!DOCTYPE html>
<html lang="en" class="[scrollbar-gutter:stable] h-full">
  <!-- Make sure to add the bg-background class and other utility classes. If there is other bg- class, you can remove it -->
  <body
    class="h-full relative antialiased bg-background [scrollbar-gutter:stable]"
  >
    <%= @inner_content %>

    <!-- Add this script -->
    <script>
      const e =
        localStorage.getItem("theme") ||
        (window.matchMedia("(prefers-color-scheme: dark)").matches
          ? "dark"
          : "light");
      document.documentElement.classList.toggle("dark", "dark" === e);
    </script>
  </body>
</html>

Acknowledgements

This project is inspired by shadcn/ui. Thank you for the amazing work you do!

Thank you to preline for their amazing work on the plugins and components that make this library possible.