Skip to content

yasmramos/tailwindfx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

115 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

TailwindFX

Utility-first UI framework for JavaFX, inspired by Tailwind CSS.

Java JavaFX License


What is TailwindFX?

TailwindFX brings Tailwind CSS's utility-first approach to JavaFX. Instead of writing boilerplate style code, you compose styles from a comprehensive set of pre-built utility classes β€” and where CSS falls short, TailwindFX provides equivalent Java APIs.

// Before β€” JavaFX vanilla
btn.setStyle(
    "-fx-background-color: #3b82f6; " +
    "-fx-text-fill: white; " +
    "-fx-background-radius: 8px; " +
    "-fx-padding: 8px 16px;"
);

// Hover animation with vanilla JavaFX

btn.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> {
    Timeline tl = new Timeline(
        new KeyFrame(Duration.ZERO,
            new KeyValue(btn.scaleXProperty(), btn.getScaleX()),
            new KeyValue(btn.scaleYProperty(), btn.getScaleY())),
        new KeyFrame(Duration.millis(150),
            new KeyValue(btn.scaleXProperty(),1.05),
            new KeyValue(btn.scaleYProperty(),1.05))
    );
    tl.play();
});

// ... same pattern for MOUSE_EXITED scaling back to 1.0

// With TailwindFX
TailwindFX.apply(btn, "btn-primary", "rounded-lg", "px-4", "py-2");
FxAnimation.onHoverScale(btn, 1.05);

Features

Feature Description
1,400+ CSS utilities Layout, typography, colors, shadows, effects, transforms
JIT compiler bg-blue-500/80, p-[13px], drop-shadow-[#3b82f6] arbitrary values
FxFlexPane Real flexbox: direction, wrap, justify-content (6), align-items (4), gap, flex-grow/shrink/basis
FxGridPane Grid-template-areas, masonry, auto-flow
FxDataTable Sortable, filterable, paginated TableView wrapper
ResponsiveNode Per-node breakpoint rules driven by Scene.widthProperty()
Themes Dark/light/blue/green/purple/rose/slate + scoped subtree themes
Animations fadeIn/Out, slideUp/Down/Left/Right, shake, bounce, pulse, spin + hover effects
Tailwind v4.1 text-shadow, drop-shadow-[color], SVG fill/stroke, 3D transforms, clip/mask
Glassmorphism TailwindFX.glass(), backdropBlur(), .glass CSS class
Neumorphism TailwindFX.neumorph(), .neumorph CSS class
ComponentFactory Cards, badges, modals, drawers, tooltips
Metrics + alerts Cache hit ratio, conflict rate, compile time alerts
Performance StyleDiff (skip redundant applies), batch apply, LRU cache

Installation

Maven

<dependency>
    <groupId>io.github.tailwindfx</groupId>
    <artifactId>tailwindfx</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

Quick Start

public class MyApp extends Application {
    @Override
    public void start(Stage stage) {
        StackPane root = new StackPane();
        Scene scene = new Scene(root, 900, 600);

        // 1. Install (loads CSS + wires breakpoints)
        TailwindFX.install(scene, stage);

        // 2. Build UI with utilities
        VBox card = new VBox(12);
        TailwindFX.apply(card, "card", "w-80");

        Label title = new Label("Hello TailwindFX");
        TailwindFX.apply(title, "text-2xl", "font-bold", "text-blue-600");

        Button btn = new Button("Get Started");
        TailwindFX.apply(btn, "btn-primary", "rounded-lg");
        FxAnimation.onHoverScale(btn, 1.05);

        card.getChildren().addAll(title, btn);
        root.getChildren().add(card);

        stage.setScene(scene);
        stage.show();
    }
}

Core APIs

Applying utilities

// Single or multiple classes:
TailwindFX.apply(node, "p-4", "bg-white", "rounded-lg", "shadow-md");

// JIT β€” arbitrary values compiled at runtime:
TailwindFX.apply(node, "bg-blue-500/80", "p-[13px]", "drop-shadow-[#3b82f6]");

// No conflict resolution (accumulate intentionally):
TailwindFX.applyRaw(node, "w-4", "w-8");  // both stay

Responsive

// Per-node rules (uses Scene.widthProperty()):
TailwindFX.responsive(sidebar)
    .base("w-64", "flex-col")
    .sm("w-full")
    .md("w-48")
    .onBreakpoint(bp -> System.out.println("Breakpoint: " + bp))
    .install(scene);

// Scene-level breakpoints:
BreakpointManager bpm = TailwindFX.responsive(stage);
bpm.onBreakpoint(BreakpointManager.Breakpoint.MD,
    () -> container.setDirection(FxFlexPane.Direction.ROW));

FxFlexPane

FxFlexPane flex = TailwindFX.flexRow()
    .wrap(true)
    .justify(FxFlexPane.Justify.BETWEEN)
    .align(FxFlexPane.Align.CENTER)
    .gap(16);

FxFlexPane.setGrow(mainContent, 1);     // flex-grow: 1
FxFlexPane.setShrink(sidebar, 0);       // flex-shrink: 0
FxFlexPane.setBasis(child, 0);          // flex-basis: 0
FxFlexPane.setAlignSelf(btn, FxFlexPane.Align.END); // align-self: end
FxFlexPane.setOrder(header, -1);        // order: -1 (first)

// Animated direction change:
flex.setDirectionAnimated(FxFlexPane.Direction.COL, 200);

FxGridPane

FxGridPane page = FxGridPane.create()
    .areas(
        "header header",
        "sidebar main",
        "footer footer"
    )
    .gap(12).build();

page.placeIn(headerRegion,  "header");
page.placeIn(sidebarRegion, "sidebar");
page.placeIn(mainContent,   "main");
page.placeIn(footerRegion,  "footer");

// Masonry layout:
FxGridPane pins = FxGridPane.create().masonry(3).gap(12).build();

FxDataTable

FxDataTable<User> table = TailwindFX.dataTable(User.class)
    .column("Name",  User::name)
    .column("Email", User::email)
    .column("Age",   u -> String.valueOf(u.age()))
    .searchable(true)
    .pageSize(25)
    .style("table-striped", "table-hover")
    .build();

table.setItems(userList);
table.setFilter(u -> u.dept().equals("Engineering"));
root.getChildren().add(table.container());

Themes

// Global theme:
TailwindFX.theme(scene).dark().apply();
TailwindFX.theme(scene).preset("blue").apply();
TailwindFX.saveTheme(scene, "myapp.theme");
TailwindFX.loadTheme(scene, "myapp.theme");

// Scoped theme (subtree only):
TailwindFX.scope(panel).preset("rose").apply();
TailwindFX.inheritScope(triggerButton, modal); // modal inherits trigger's scope
TailwindFX.refreshScope(panel);                // after reparenting

Animations

FxAnimation.fadeIn(node, 300).play();
FxAnimation.slideUp(node).play();
FxAnimation.shake(button).play();        // validation error
FxAnimation.spin(loadingIcon).loop().play();

FxAnimation.onHoverScale(btn, 1.05);    // permanent hover scale
FxAnimation.onHoverLift(btn);           // hover lift (-4px)
FxAnimation.onHoverDim(btn, 0.8);       // hover dim
FxAnimation.removeHoverEffects(btn);    // clean up all hover effects

// Chain / parallel:
FxAnimation.chain(fadeIn, slideUp).play();
FxAnimation.parallel(pulse, bounce).play();

// Reduced motion:
TailwindFX.setReducedMotion(true);
TailwindFX.playIfMotionOk(animation);  // plays or jumps to end state

Tailwind v4.1

// Text shadow:
TailwindFX.textShadowMd(heading);
TailwindFX.textShadow(label, "#3b82f6", 6, 0, 2);  // colored

// Colored drop shadow:
TailwindFX.dropShadowBlue(card);
TailwindFX.dropShadow(card, "#22c55e", 0.4, 12, 0, 4);

// Clip/mask:
TailwindFX.clipCircle(avatar);
TailwindFX.clipRounded(imageView, 12);

// 3D transforms:
TailwindFX.rotateX(panel, 15);
TailwindFX.rotateY(card, 30);
TailwindFX.translateZ(tooltip, 50);

// Glass / neumorph:
TailwindFX.glass(overlayPane);
TailwindFX.backdropBlurMd(overlayPane);
TailwindFX.neumorph(button);

// SVG:
TailwindFX.fill(svgPath, "#3b82f6");
TailwindFX.stroke(svgPath, "#000000");

Metrics & alerts

TailwindFX.metrics()
    .setEnabled(true)
    .onAlert((metric, value, threshold) ->
        System.err.printf("Alert: %s=%.2f%n", metric, value))
    .alertOnLowCacheHitRatio(0.70)
    .alertOnHighConflictRate(0.30)
    .alertOnSlowCompile(0.5);   // ms

TailwindFX.metrics().print(); // formatted report

Performance

// Batch apply (1 CSS pass for many nodes):
TailwindFX.batch(() ->
    cards.forEach(c -> TailwindFX.apply(c, "card", "shadow-md")));

// Configure auto-batch threshold:
TailwindFX.configure().autoBatch(20);

// Cleanup on node removal:
TailwindFX.cleanupNode(removedNode);   // explicit
TailwindFX.autoCleanup(cellNode);      // auto on scene removal

License

MIT β€” see LICENSE for details.


Contributing

We welcome contributions from the community! Here's how you can help:

  1. Check existing issues - Look for Good First Issues to get started
  2. Read our guides - See CONTRIBUTING.md and CODE_OF_CONDUCT.md
  3. Fork and submit PRs - Create a branch from develop, make your changes, and submit a pull request
  4. Report bugs - Use our bug report template
  5. Suggest features - Use our feature request template

Quick Links


About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors