Skip to content

Instantly share code, notes, and snippets.

@rzv-me
Last active May 31, 2025 08:17
Show Gist options
  • Save rzv-me/ee3520b2d33df6de95dd2eb444c344ba to your computer and use it in GitHub Desktop.
Save rzv-me/ee3520b2d33df6de95dd2eb444c344ba to your computer and use it in GitHub Desktop.
Add arrows to Flux UI v2 tooltips

There are 2 options for adding arrows to the Flux UI v2 tooltips

  1. add the content of app.css to your
  2. add the classes directly to the flux/tooltip/content.blade.php

FYI, this is just a PoC and can be improved

1. Add the classes to your app.css

  • publish the tooltip blades php artisan flux:publish Tooltip
  • copy the css-version_app.css from this gist to your app.css
  • copy the content of css-version_tooltip_content.blade.php to resources/views/flux/tooltip/content.blade.php
  • copy the content of tooltip_index.blade.php to resources/views/flux/tooltip/index.blade.php
  • update function anchor(....) in flux.js: change the then(...) call. Use code from the file in this gist

2. Add the classes directly to the flux/tooltip/content.blade.php

  • publish the tooltip blades php artisan flux:publish Tooltip
  • copy the content of class-version_tooltip_content.blade.php to resources/views/flux/tooltip/content.blade.php
  • copy the content of tooltip_index.blade.php to resources/views/flux/tooltip/index.blade.php
  • update function anchor(....) in flux.js: change the then(...) call. Use code from the file in this gist
@props([
'kbd' => null,
'arrow' => false,
])
@php
$classes = Flux::classes([
'relative py-2 px-2.5',
'rounded-md',
'text-xs text-white font-medium',
'bg-zinc-800 dark:bg-zinc-700 dark:border dark:border-white/10',
'p-0 !overflow-visible',
]);
if ($arrow) {
$classes = $classes->add([
'before:absolute',
'before:w-1.5 before:h-1.5',
'before:bg-zinc-800',
'dark:before:bg-zinc-700 dark:before:border-r dark:before:border-b dark:before:border-white/10',
// position: top
'data-[position=top]:before:bottom-0 data-[position=top]:before:rotate-45 data-[position=top]:dark:before:-mb-[4px] data-[position=top]:before:-mb-[3px]',
// position: bottom
'data-[position=bottom]:before:top-0 data-[position=bottom]:before:-rotate-135 data-[position=bottom]:dark:before:-mt-[4px] data-[position=bottom]:before:-mt-[3px]',
'data-[placement=vertical-center]:before:left-[50%] data-[placement=vertical-center]:before:-ml-[6px]',
'data-[placement=vertical-start]:before:left-0 data-[placement=vertical-start]:before:ml-[6px]',
'data-[placement=vertical-end]:before:right-0 data-[placement=vertical-end]:before:mr-[6px]',
// position: left
'data-[position=left]:before:right-0 data-[position=left]:before:-rotate-45 data-[position=left]:dark:before:-mr-[4px] data-[position=left]:before:-mr-[3px]',
// position: right
'data-[position=right]:before:left-0 data-[position=right]:before:rotate-135 data-[position=right]:dark:before:-ml-[4px] data-[position=right]:before:-ml-[3px]',
'data-[placement=side-center]:before:bottom-[50%] data-[placement=side-center]:before:-mb-[3px]',
'data-[placement=side-start]:before:top-0 data-[placement=side-start]:before:mt-[6px]',
'data-[placement=side-end]:before:bottom-0 data-[placement=side-end]:before:mb-[6px]',
]);
}
@endphp
<div popover="manual" {{ $attributes->class($classes) }} data-flux-tooltip-content>
{{ $slot }}
<?php if ($kbd): ?>
<span class="ps-1 text-zinc-300">{{ $kbd }}</span>
<?php endif; ?>
</div>
[data-flux-tooltip-content][data-flux-show-arrow] {
@apply before:absolute;
@apply before:w-1.5 before:h-1.5;
@apply before:bg-zinc-800;
@apply dark:before:bg-zinc-700 dark:before:border-r dark:before:border-b dark:before:border-white/10;
/* position: top */
@apply data-[position=top]:before:bottom-0 data-[position=top]:before:rotate-45 data-[position=top]:dark:before:-mb-[4px] data-[position=top]:before:-mb-[3px];
/* position: bottom */
@apply data-[position=bottom]:before:top-0 data-[position=bottom]:before:-rotate-135 data-[position=bottom]:dark:before:-mt-[4px] data-[position=bottom]:before:-mt-[3px];
@apply data-[placement=vertical-center]:before:left-[50%] data-[placement=vertical-center]:before:-ml-[6px];
@apply data-[placement=vertical-start]:before:left-0 data-[placement=vertical-start]:before:ml-[6px];
@apply data-[placement=vertical-end]:before:right-0 data-[placement=vertical-end]:before:mr-[6px];
/* position: left */
@apply data-[position=left]:before:right-0 data-[position=left]:before:-rotate-45 data-[position=left]:dark:before:-mr-[4px] data-[position=left]:before:-mr-[3px];
/* position: right */
@apply data-[position=right]:before:left-0 data-[position=right]:before:rotate-135 data-[position=right]:dark:before:-ml-[4px] data-[position=right]:before:-ml-[3px];
@apply data-[placement=side-center]:before:bottom-[50%] data-[placement=side-center]:before:-mb-[3px];
@apply data-[placement=side-start]:before:top-0 data-[placement=side-start]:before:mt-[6px];
@apply data-[placement=side-end]:before:bottom-0 data-[placement=side-end]:before:mb-[6px];
}
@props([
'kbd' => null,
'arrow' => false,
])
@php
$classes = Flux::classes([
'relative py-2 px-2.5',
'rounded-md',
'text-xs text-white font-medium',
'bg-zinc-800 dark:bg-zinc-700 dark:border dark:border-white/10',
'p-0 !overflow-visible',
]);
@endphp
<div popover="manual" {{ $attributes->class($classes) }} data-flux-tooltip-content {{ $arrow ? 'data-flux-show-arrow' : '' }}>
{{ $slot }}
<?php if ($kbd): ?>
<span class="ps-1 text-zinc-300">{{ $kbd }}</span>
<?php endif; ?>
</div>
function anchor(target, invoke, setPosition, { position, offset: offsetValue, gap, matchWidth, crossAxis, scrollY }) {
let elMaxHeight = window.getComputedStyle(target).maxHeight;
elMaxHeight = elMaxHeight === "none" ? null : parseFloat(elMaxHeight);
return (event, forceX, forceY) => {
computePosition2(invoke, target, {
placement: compilePlacement(position),
// Placements: ['top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end']
middleware: [
// Offset needs to be first, as per the Floating UI docs...
offset2({
mainAxis: Number(gap),
alignmentAxis: Number(offsetValue)
}),
flip2(),
shift2({ padding: 5, crossAxis }),
size2({
padding: 5,
apply({ rects, elements, availableHeight }) {
if (matchWidth) {
Object.assign(elements.floating.style, {
width: `${rects.reference.width}px`
});
}
let maxHeight = elMaxHeight;
if (maxHeight === null) {
maxHeight = scrollY ? elements.floating.scrollHeight : elements.floating.offsetHeight;
}
elements.floating.style.maxHeight = availableHeight > maxHeight ? "" : `${availableHeight}px`;
}
})
]
}).then(({ x, y, placement }) => {
setPosition(forceX || x, forceY || y);
const [position, alignment] = placement.split("-");
const orientation = (position === "left" || position === "right") ? "side" : "vertical";
target.setAttribute('data-placement', `${orientation}-${alignment}`);
target.setAttribute('data-position', position);
target.setAttribute('data-alignment', alignment);
});
};
}
@props([
'interactive' => null,
'position' => 'top',
'align' => 'center',
'content' => null,
'kbd' => null,
'toggleable' => null,
'arrow' => false,
])
@php
// Support adding the .self modifier to the wire:model directive...
if (($wireModel = $attributes->wire('model')) && $wireModel->directive && ! $wireModel->hasModifier('self')) {
unset($attributes[$wireModel->directive]);
$wireModel->directive .= '.self';
$attributes = $attributes->merge([$wireModel->directive => $wireModel->value]);
}
@endphp
<?php if ($toggleable): ?>
<ui-dropdown position="{{ $position }} {{ $align }}" {{ $attributes }} data-flux-tooltip>
{{ $slot }}
<?php if ($content !== null): ?>
<flux:tooltip.content :$kbd :arrow>{{ $content }}</flux:tooltip.content>
<?php endif; ?>
</ui-dropdown>
<?php else: ?>
<ui-tooltip position="{{ $position }} {{ $align }}" {{ $attributes }} data-flux-tooltip @if ($interactive) interactive @endif>
{{ $slot }}
<?php if ($content !== null): ?>
<flux:tooltip.content :$kbd :arrow>{{ $content }}</flux:tooltip.content>
<?php endif; ?>
</ui-tooltip>
<?php endif; ?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment