Layouts

Patterns

Every design decision in flux was carefully and intentionally made. Understanding these intentions will make your experience with flux more intuitive.


Ideally, after internalizing some of flux's design philosophy, you will be able to almost guess how to use a component you're unfamiliar with.

Props vs attributes

Props and attributes are indistinguishable on the surface, however, we've found it helpful to make a distinction between flux-provided properties called "props" and bespoke "attributes" that will be forwarded directly to an underlying HTML element.
For example, the following component uses a prop called
variant
as well as a bespoke
x-on:change.prevent
attribute:
Copy to clipboard
When the component is rendered in the browser, the output HTML might will look something like this:
Copy to clipboard
As you can see, the
x-on:change.prevent
attribute was forwarded directly to the underlying HTML element, while the
variant
prop was instead internally used to customize which classes were applied to the input.

Class merging

Most flux components apply Tailwind classes to their underlying elements, however, you can also pass your own classes into components and they will be automatically merged with the classes applied by flux.
Here's an example of making a button full width by passing in the
w-full
Tailwind utility class:
Copy to clipboard
Now, when the component is rendered, the output HTML will contain both the
w-full
class and other classes applied by flux:
Copy to clipboard

Dealing with class merging conflicts

Occasionally, you may run into conflicts when passing in a Tailwind utility that flux also applies internally.
For example, you may try to customize the background color of a button by passing in the
bg-zinc-800
Tailwind utility class:
Copy to clipboard
However, because flux applies it's own
bg-*
attributes, both classes will be rendered in the output HTML:
Copy to clipboard
Because both classes exist on the element, the one defined last in CSS wins.
Tailwind's important (
!
) modifier is the simplest way to resolve these conflicts:
Copy to clipboard
The conflicting utilities will still both be rendered, however the user-defined ones with the
!
modifier will take precedence.
Usage of the
!
modifier can cause more problems than it solves. Below are a few alternatives to consider instead:
  • Publishing the component and adding your own variant
  • Globally customizing the component by styling the data attributes
  • Writing a new component for your unique case

Split attribute forwarding

In a perfect world, each flux component would directly render a single HTML element. However, in practice, some components are more complex than that.
For example, the
flux:input
component actually renders two HTML elements by default. A wrapping
<div>
and an underlying
<input>
element:
Copy to clipboard
This presents a problem when passing bespoke Tailwind classes into the component: which element should receive the provided classes?
In these cases flux will often split up the forwarded attributes into two groups: styling related ones like
class
and behavioral ones like
autofocus
. It will then apply each to wherever is most appropriate.
For example consider passing in the following
class
and
autofocus
attributes:
Copy to clipboard
Flux will apply the
w-full
class to the wrapping
<div>
element and the
autofocus
attribute to the underlying
<input>
element:
Copy to clipboard

Common props

Now that you've seen some of the nuances of attributes, let's look at some common prop patterns you will encounter as you use Flux.

Variant

First up is "variant". Any component that offers an alternate visual style uses the
variant
prop to do so.
Here's a list of a few common component variants:
Copy to clipboard
If you find the need for a variant we don't offer, don't be afraid to publish a component and add your own.

Icon

Rather than manually adding, styling, and spacing icons inside component slots, you can simply pass the
icon
prop to any component that supports it.
Flux uses Heroicons for its icon collection. Heroicons is a set of beautiful and functional icons crafted by the fine folks at Tailwind Labs.
Here's a handful of components you can pass icons into:
Copy to clipboard
Occasionally, if a component supports adding an icon to the end of an element instead of the beginning by default, you can pass the
icon-trailing
prop as well:
Copy to clipboard

Size

Some components offer size variations through the
size
prop.
Here are a few components that can be sized-down:
Copy to clipboard
Here are a few that can be sized up for larger visual contexts:
Copy to clipboard

Keyboard hints

Similar to the
icon
prop, many components allow you to add decorative hints for keyboard shortcuts using the
kbd
prop:
Copy to clipboard

Inset

Certain components offer the
inset
prop which makes it easy to add the exact amount of negative margin needed to "inset" an element on any axis you specify.
This is extremely useful for putting a button or a badge inline with other text and not stretching the entire height of the container.
Copy to clipboard

Prop forwarding

Occasionally, one component will wrap another and expose it as a simple prop.
For example, here is the Button component that allows you to set the icon using the simple
icon
prop instead of passing an entire Icon component into the Button as a child:
Copy to clipboard
This is often a more desirable alternative to composing the entire component like so:
Copy to clipboard
However, when using the
icon
prop, you are unable to add additional props to the Icon component like
variant
.
In these cases, flux will often expose nested props via prefixes like so:
Copy to clipboard

Opt-out props

Sometimes flux will turn a prop "on" by default, or manage its state internally. For example, the
current
prop on the
navbar.item
component.
However, you may want to enforce that its value remains
false
for a specific instance of the component.
In these cases, you can use Laravel's dynamic prop syntax (
:
) and pass in
false
.
Copy to clipboard

Shorthand props

Sometimes a component arrangement is both common and verbose enough that it warrants a shorthand syntax.
For example, here's a full input field:
Copy to clipboard
This can be shortened to the following:
Copy to clipboard
Internally, flux will expand the above into the full assembly of
field
,
label
,
input
, and
error
components.
This way you can keep syntax short and concise, but still have the ability to fully customize things if you'd like to use the full longform syntax.
You'll also encounter this pattern with tooltips and buttons.
Here's a long-form toolip:
Copy to clipboard
Because the above is often repetitive, you can shorten it to a simple
tooltip
prop:
Copy to clipboard

Data binding

In Livewire you are used to adding
wire:model
directly to input elements inside your forms.
In Flux, the experience is no different. Here are some common components you will often be adding
wire:model
to:
Copy to clipboard
In addition to these common ones you'd expect, here are a few other components you can control via
wire:model
:
Copy to clipboard
Of course, you can also pass
x-model
or
x-on:change
to any of these and they should behave exactly like native input elements.

Component Groups

When a Flux component can be "grouped", but is otherwise a stand-alone component, its wrapper component has a
.group
suffix.
All of the following components can be used on their own, or grouped together:
Copy to clipboard
Alternatively, if a component can NOT be used on its own, but can be grouped, the wrapper will often be the main name of the component, and each child will have a
.item
suffix:
Copy to clipboard

Root components

Most of the time, when a component can be composed of many sub-components, you will see compound names like the ones mentioned above.
However, for components that are larger or more "primitive" feeling than the others, they will lack a common prefix, and instead use the name of the component itself.
For example, this is flux's field component:
Copy to clipboard
You'll notice bare component names like
flux:label
, instead of
flux:field.label
.
The reasoning for this is to avoid overly verbose heirarchies in common components that would result in naming like:
flux:field.label.badge
.
You will also see this pattern with
<flux:table>
.

Anomalies

As painful as it is, sometimes for something to "feel right", you have to abandon consistency for one reason or another.
For example, the
flux:tabs
component doesn't follow the aforementioned rules:
Copy to clipboard

Slots

In general, Flux prefers composing multiple components together rather than using slots.
However, there are times where there is no substitute and slots are the perfect solution.
To demonstrate, consider the following input component with an
x-mark
icon:
Copy to clipboard
If you wanted to wrap the icon in a clickable button to perform an action there is no way to achieve that without slots (or without offering an extremely verbose, custom syntax).
Here is the above, rewritten with a wrapping button:
Copy to clipboard

Paper cuts

Here are a few gotchas that you might encounter while using Flux.

Blade components vs HTML elements

When dealing with plain HTML elements in Blade, you are free to use expressions like
@if
inside opening tags.
However, those expressions are not supported inside the opening tag of a Blade or Flux component.
Instead, you must stay within the confines of the Blade component dynamic attribute syntax:
Copy to clipboard
Copyright © 2024 Wireable LLC · Terms of Service
Built with
by Caleb Porzio and Hugo Sainte-Marie