The Changelog

What's new around here?

Succinct and informative updates about Flux.
December 17, 2024

Theming in Flux

Version ^1.1.0
A rich text editor with a toolbar
Don't want your Flux app looking like everybody else's? We've got you covered. Flux is now completely themeable!

Three colors, one accent

A rich text editor with a toolbar
In a perfect world, you could pick a single accent color to theme your entire app. Unfortunately, we found this to be a pipe dream. Instead, we've learned you need no fewer than three accent colors in a system that can support every hue:
  • The base accent color. Used for things like the primary button background
  • A foreground color. This sits on-top of the base accent color; often used in text.
  • A content color. A stronger variant of the accent color for thinner figures like text.
We can then tweak those colors using opacity or color-mix() for specific needs, but those are the three core colors to work off of.

Hand picked colors

A rich text editor with a toolbar
We've curated themes for every color in the Tailwind color palette. Each combination is hand selected to make sure it looks just right.
For example, we chose a dark foreground color, instead of white, when an accent color like yellow is too light to meet color contrast standards.

Dark mode

A rich text editor with a toolbar
Of course each theme has dark mode baked in, but this is not your mother's dark mode.
There are plenty of places where we went a completely different route stylistically to make sure all designs "feel" the same in both light and dark mode.
One example is when you hover over a radio card in light mode, the background and border are set to a subtle hue of your accent color, however, in dark mode, the card is just a lighter shade of gray.
This is because when you add color to an element in light mode it looks lighter and therefore closer to the user. But when you add color to an element in dark mode, it looks DARKER, and therefore further from the user and more blended with the background. In these cases, we've mixed the color with extra white—using transparency—or left the color out completely.

Opt-out

Some components are themed by default that you may want to render as a base color instead.
In these cases, we've added an accent prop that you can use to opt-out of the themed version.
Here's an example of rendering a link in black/white instead of your accent color:
Copy to clipboard
<flux:link :accent="false">Profile</flux:tab>

Choose your gray

A rich text editor with a toolbar
Flux ships with zinc as its gray hue of choice. This looks clean and modern with its black and white design, however, it's not always the best choice for other accent colors.
We've pre-selected which gray colors look best in combination with certain accent colors. You can simply select an accent color in the theme builder, and we will adapt the gray to match.
Of course, you can also choose your own gray if you have a different preference.

CSS Variables

Copy to clipboard
@layer base {    :root {        --color-accent: var(--color-amber-400);        --color-accent-content: var(--color-amber-600);        --color-accent-foreground: var(--color-amber-950);    }    .dark {        --color-accent: var(--color-amber-400);        --color-accent-content: var(--color-amber-400);        --color-accent-foreground: var(--color-amber-950);    }}
We are using CSS variables for all accent colors so they can be easily customized in any way you please.
We've also chosen variable names that adhere to Tailwind 4's naming convention. This way, in Tailwind 4, you won't need to add any configuration to use them in your utilities like bg-accent.
You'll also notice these variables are adaptive, meaning they will change their values automatically in dark mode so that you don't have to do things like: bg-accent dark:bg-accent-dark.

Tailwind 4, here we come

A rich text editor with a toolbar
With Tailwind 4 right around the corner, we wanted to make sure we taking advantage of all the goodness it has to offer as well as using conventions like the aforementioned variable names.
Tailwind 4 uses a more modern color space for its color palette called oklab instead of the standard srgb (hsa(), rgb(), etc.) that you're used to.
Here is the difference between bg-red-500 in Tailwind 3 vs Tailwind 4:
Copy to clipboard
/* Tailwind 3 */--color-red-500: #ef4444;/* Tailwind 4 */--color-red-500: oklch(0.637 0.237 25.331);
This unlocks an entire new level of color (on modern monitors) that we were previously unable to render.
Therefore, you'll notice all colors in Flux themes are more vibrant than anything you would have seen in Tailwind 3.
In the interim, we've copied every CSS color variable to Flux from Tailwind 4's public beta. When Tailwind 4 is released, we'll be able to drop these and just use the ones Tailwind ships with.

We've spent countless hours researching and experimenting with everything theme related and are very happy with where we've landed. We hope you are too.
December 12, 2024

Dark mode controls

Version ^1.0.30
A dark mode radio switcher
Flux has always supported dark mode in the sense that when your system appearance changes, Flux adapts.
However, there's a big gap between that kind of dark mode support, and providing controls to fully control dark mode for a site independently of system preferences.
Before we get into the details, just take a look at how simple it is now to create a dark mode switcher like the one shown above. Here is the exact code that was used for that switcher:
Copy to clipboard
<flux:radio.group variant="segmented" x-model="$flux.appearance">    <flux:radio value="light" icon="sun">Light</flux:radio>    <flux:radio value="dark" icon="moon">Dark</flux:radio>    <flux:radio value="system" icon="computer-desktop">System</flux:radio></flux:radio.group>
Here's another code snippet to make an even simpler toggle button:
Copy to clipboard
<flux:button x-on:click="$flux.dark = ! $flux.dark" ... />

New JavaScript APIs

As you might have noticed in the code snippets above, Flux now ships with a magic $flux object available to you inside Alpine expressions.
There are two dark-mode related affordances on this magic object: .dark and .appearance.
You can get/set the dark state of an app using the $flux.dark boolean property. You can also get/set the theme preference for an app using the $flux.appearance property (which will be one of three values: light, dark, and system).
Given these two simple properties, you should be able to accomplish any type of dark mode control widget you'd like. For example, a dark mode select, a dropdown menu, a toggle button, a toggle switch, radio groups, cards, or segmented radios. The sky's the limit.
If you need control from outside of Alpine, we've also shipped a global Flux object on the window called window.Flux.
Now, you can do something like this:
Copy to clipboard
let button = document.querySelector('...')button.addEventListener('click', () => {    Flux.dark = ! Flux.dark})

What's going on under the hood?

Out of the box, Flux will add/remove a .dark class to the <body> element of your page.
This means you can easily configure Tailwind to honor this class instead of the system preference using Tailwind configuration like so:
Copy to clipboard
module.exports = {    darkMode: 'selector',    ...}
Flux takes care of all the tricky bits like storing the user appearance preference in local storage to persist that choice between page loads.
We are also listening for system preference changes at run-time so that we can adapt the site without waiting for a new page load.
Doing these things yourself is not rocket science, but it certainly is more complicated than you want it to be. Enjoy.
November 24, 2024

Rich text editor

Version ^1.0.27
A rich text editor with a toolbar
Welp, we did it. As of today, Flux now ships with a rich text editor 🎉.
Just slap this one-liner anywhere in your app and you're off and editing:
Copy to clipboard
<flux:editor wire:model="content" />
We really sweat the details on this one and hope it shows.

Configurable toolbar

A rich text editor with a different toolbar configuration than before
Copy to clipboard
<flux:editor toolbar="heading | bold italic strike ~ link" />
To configure an editor's toolbar items, you can pass a custom arrangement into the toolbar prop as a string of item names mixed with separators (|) and spacers (~).
Because each of these items is a simple Blade component inside Flux, you can easily create your own Blade components and reference them by name inside the toolbar prop.

Custom toolbar items

An editor with a custom dropdown menu in the toolbar
If you want complete control over the toolbar, you can compose your own editor by assembling the Blade components yourself.
Here's an example of adding a custom dropdown menu to an editor's toolbar:
Copy to clipboard
<flux:editor>    <flux:editor.toolbar>        <flux:editor.heading />        <flux:editor.separator />        <flux:editor.bold />        ...        <flux:dropdown>            <flux:editor.button icon="ellipsis-horizontal" tooltip="More" />            <flux:menu>                <flux:menu.item wire:click="..." icon="arrow-top-right-on-square">Preview</flux:menu.item>                <flux:menu.item wire:click="..." icon="arrow-down-tray">Export</flux:menu.item>                <flux:menu.item wire:click="..." icon="share">Share</flux:menu.item>            </flux:menu>        </flux:dropdown>    </flux:editor.toolbar>    <flux:editor.content /></flux:editor>
As you can see, this is just Blade/HTML like any other component. You can style and assemble any other Flux components you like into the editor's toolbar.

Mouse optional

Showing there is only one tab stop at a time on the editor toolbar
The editor's toolbar uses a roving tabindex so that you don't have to tab through every toolbar item as you tab along the page. The toolbar acts as a single tab stop that you can navigate using the arrow keys.
You can navigate sub menus within the toolbar using only your keyboard as well.
In fact, you can operate everything about this editor, easily, without ever touching your mouse.

Markdown syntax

Typing markdown syntax into the editor to trigger formatting
Although this is a rich text editor, it supports Markdown syntax as a convenient way to control styling in your document as you edit.

Shortcuts

All the available toolbar operation icons in a row
All the standard keyboard shortcuts you're familiar with from other editors like Google Docs are available to use as well.
Here are a few examples:
  • Cmd+B Bold
  • Cmd+I Italic
  • Cmd+K Insert link

As a form field

An editor with a form field label and description
Copy to clipboard
<flux:editor label="Release notes" description="Explain what’s new in this release." />
We wanted this component to feel no different than a textarea field when using it inside a form.
This means tackling things like disabled and invalid states at both the field AND fieldset level, associating labels/descriptions with the editor, as well as focusing the editor when the field label is clicked.

Screen readers

A screenshot of the editor's accessibility tree in Chrome devtools
As you can see by the figure above, we worked hard to make sure the editor's accessibility tree was as descriptive and functional as possible.
Screen readers can easily discover and use all features inside the editor. This includes the tricky bits like toolbar sub-selects, tooltips, and insert-link popovers.

Dynamic JS bundle

Currently, every bit of Flux's JavaScript is contained inside a 21.5KB file.
Because of the enormity of a rich text editor and its dependancies, this component would add a whopping 85.3KB to the the Flux bundle size.
The problem is that many pages in an app don't use a rich-text editor at all and it doesn't make sense to penalize them with a bigger bundle.
Therefore, we included the editor's JavaScript as a separate bundle that gets loaded in parallel on an as-needed basis. The editor's JS will only be included at the exact moment it's needed to keep everything else in your app feeling light and snappy. This includes edge cases like lazy-loading an editor long after a page has already been loaded.

Localization

A screenshot of editor tooltip in spanish
All of the english copy used in this component is translatable by copying a predefined set of keys into your lang/?.json files.

Built on Tiptap & ProseMirror

Rather than wrapping a more batteries-included editor like Quill or TinyMCE, we opted to use Tiptap under the hood for the editor's core functionality.
Tiptap is a convenience wrapper around the extremely powerful ProseMirror project.
It's completely headless, meaning we have full control over all of the markup, visuals, and accessibility, without having to be responsible for the input/formatting interactions.
This means we can make the toolbar as customizable as everything else in Flux because we own all the HTML/CSS/JS for it.
Also, to help support and thank the ProseMirror project, we donated $1000 via their GitHub sponsors profile.

The future

For launch our goal was: a rock-solid editor that feels just as good to develop and use as any other component in Flux.
Now that we've accomplished that, we can start adding next-level features like image support and @mentions.
Stay tuned!
Copyright © 2025 Wireable LLC ·Terms of Service
Built with by
Caleb Porzio and Hugo Sainte-Marie