Introduction

Re-usable server-side components based on shadcn/ui.
Built with JinjaX, Alpine.js, and Tailwind CSS, with support for htmx.

Modern Server-Side Components

This project brings the component design patterns of shadcn/ui to the Python ecosystem. It's an unofficial port that leverages modern tools like JinjaX, Alpine.js, and htmx to create dynamic, responsive components with server-side rendering.

Note: This project is not affiliated with shadcn.

Features

  • Modern Stack: Combines JinjaX for components, Alpine.js for reactivity, and htmx for dynamic behavior in HTML
  • Server-First: Built specifically for Python web frameworks (FastAPI, Django, Flask)
  • Customizable: Every component is yours to modify and extend
  • Minimal Dependencies: Copy only the components you need - no package to install. You'll need to set up Tailwind CSS and include Alpine.js, htmx, and JinjaX in your project.
  • Accessibility: Maintains the accessibility features of shadcn/ui
  • Light and Dark: Built-in theming support with light and dark modes

Not a Traditional Component Library

This is not a traditional component library that you install as a dependency into a virtualenv. Instead, it's a collection of reusable components that you can copy directly into your project.

  1. Choose the components you need
  2. Use the CLI to add them to your project (or copy/paste manually)
  3. Configure your code to use the components
  4. Customize the code to match your needs
  5. Build your interface using JinjaX's component system and Tailwind CSS's utility classes for styling and htmx for dynamic updates

Here's a simple example

You can include a component using simple HTML tags in a Jinja template. Additional behavior can be added via attributes for Alpine.js or htmx. Click the Alpine enabled and htmx enabled buttons below.

<!-- style variants defined in the component -->
<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="link">Link</Button>

<!-- use alpine.js -->
<Button
        x-on:click="alert('So easy!')"
        variant="ghost">Alpine enabled</Button>

<!-- use htmx -->
<Button
        variant="outline"
        hx-get="/demo/button"
        hx-trigger="click"
        hx-target="this"
        hx-swap="outerHTML">htmx enabled</Button>

Components are implemented using JinjaX and contain all the info about styles and any logic required for behavior.

{#def
    className: str = "",
    variant: str = "default",
    size: str = "default",
    disabled: bool = False
#}
{% set baseclassName = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-zinc-950 dark:focus-visible:ring-zinc-300" %}
{% set variantclassName = {
    'default': 'bg-zinc-900 text-zinc-50 hover:bg-zinc-900/90 dark:bg-zinc-50 dark:text-zinc-900 dark:hover:bg-zinc-50/90',
    'destructive': 'bg-red-500 text-zinc-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-zinc-50 dark:hover:bg-red-900/90',
    'outline': 'border border-zinc-200 bg-white hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-50 dark:border-zinc-700 dark:bg-zinc-950 dark:hover:bg-zinc-800 dark:hover:text-zinc-50',
    'secondary': 'bg-zinc-100 text-zinc-900 hover:bg-zinc-100/80 dark:bg-zinc-800 dark:text-zinc-50 dark:hover:bg-zinc-800/80',
    'ghost': 'hover:bg-zinc-100 hover:text-zinc-900 dark:hover:bg-zinc-800 dark:hover:text-zinc-50',
    'link': 'text-zinc-900 underline-offset-4 hover:underline dark:text-zinc-50'
  }[variant] %}
{% set sizeclassName = {
    'default': 'h-10 px-4 py-2',
    'sm': 'h-9 rounded-md px-3',
    'lg': 'h-11 rounded-md px-8',
    'icon': 'h-10 w-10'
  }[size] %}
<button
    class="{{ baseclassName }} {{ variantclassName }} {{ sizeclassName }} {{ className }}"
    {% if disabled %}disabled{% endif %}
    {{ attrs.render() }}
>
  {{ content }}
</button>
Components are easily composable, allowing you to combine them to create complex layouts using Tailwind utility classes.

Your Orders
Introducing Our Dynamic Orders Dashboard for Seamless Management and Insightful Analysis.
<Card className="w-[350px] mb-4">
  <CardHeader className="pb-3">
    <CardTitle>Your Orders</CardTitle>
    <CardDescription className="max-w-lg text-balance leading-relaxed">
      Introducing Our Dynamic Orders Dashboard for Seamless Management and
      Insightful Analysis.
    </CardDescription>
  </CardHeader>
  <CardFooter>
    <Button>Create New Order</Button>
  </CardFooter>
</Card>

Project Status

This is an active project, with new components being added regularly. We welcome your feedback and contributions! See the changelog for details and check out the contribution guide to get involved!

FAQ

Why copy/paste?

Traditional component libraries often couple style with implementation, making customization difficult. By providing components you can copy and modify: - You have complete control over the implementation and styling. - You can customize the components to suit your needs. - You maintain full control by copying the code directly

Which frameworks are supported?

Any Python web framework that supports Jinja templates works with these components. Setup guides for FastAPI, Django, and Flask with complete examples are included.

Can I use this in my project?

Yes! This project is MIT licensed and free to use in personal and commercial projects. No attribution required.

Why did you create this?

The project was created to provide a way to build full-stack applications using server-side rendering, with Alpine.js and htmx for interactivity and Tailwind CSS for styling. Traditional Jinja templates with standard patterns like extending and including templates can become messy, especially with numerous Tailwind utility classes. Using JinjaX, along with Tailwind CSS and htmx, enables a clean and maintainable pattern for composing components that are easy to extend and debug. Read more here.

Component X is missing

We plan to port all components from shadcn/ui. However, you don't need to wait—feel free to contribute by adding it yourself! Most components are straightforward to port, and we've included a guide that we've followed, using AI to handle much of the heavy lifting. Your contributions are welcome and appreciated.