gitea icon indicating copy to clipboard operation
gitea copied to clipboard

Fomantic UI replacements via web components

Open silverwind opened this issue 1 year ago • 21 comments

Feature Description

As many know, we want to get rid of Fomantic UI. I propose the following:

  • Change the remaining easy-to-replace components with custom implementations in JS/CSS
  • For harder-to-replace components like dropdown and modal, use web components, ideally from npm dependencies.

I think custom elements are the future for Gitea's UI as they work on both backend-rendered content as well as frameworks like Vue and React.

We should first investigate if there are suitable web components available for these modules. Requrement for them is that they have good a11y and they need to be headless (e.g. no CSS).

If no suitable npm modules are available, we can write our own like was recently done for <overflow-menu> and <absolute-date>.

silverwind avatar Mar 16 '24 16:03 silverwind

https://github.com/shoelace-style/shoelace looks like a interesting library of web components. It uses floating-ui so should be top-notch for placment of floating content.

silverwind avatar Mar 16 '24 23:03 silverwind

Some of the components may be rarely used. What about implementing them via tailwindcss?

harryzcy avatar Mar 17 '24 01:03 harryzcy

What does "implementing via tailwindcss" exactly mean? You can't implement stuff like interactivity, reactivity, a11y and many other things with CSS alone.

silverwind avatar Mar 17 '24 01:03 silverwind

What does "implementing via tailwindcss" exactly mean? You can't implement stuff like interactivity, reactivity, a11y and many other things with CSS alone.

I get it. I only mean some CSS only UI components.

harryzcy avatar Mar 17 '24 01:03 harryzcy

Sure, what can be done with CSS only should be done with it. But I'm really talking about the more complex components like Dropdown and Modal which will require JS.

silverwind avatar Mar 17 '24 01:03 silverwind

https://github.com/shoelace-style/shoelace looks like a interesting library of web components. It uses floating-ui so should be top-notch for placment of floating content.

@silverwind This looks really promising, did you try it already? There are lots of styling options....

denyskon avatar Mar 20 '24 17:03 denyskon

Did not try it yet, but first we should assert that the a11y of these components is ok. We should not blindly trust their claims 😆.

silverwind avatar Mar 20 '24 17:03 silverwind

@wxiaoguang I've seen you evaluating a11y for some components. What do you normally test? I'd really like if we could replace fomantic soon, but as silverwind said we need to check a11y for these components first 😅

denyskon avatar Mar 31 '24 09:03 denyskon

There are some details in aria.md. Usually: the screen content could be read out correctly, the a11y active element could be highlighted and switched correctly. Actually the most difficult part is "dropdown ( menu / select / combobox / popup )". Other components are quite easy to work with native a11y support.

wxiaoguang avatar Mar 31 '24 09:03 wxiaoguang

@wxiaoguang maybe you can review these components for their accessibility:

  • https://shoelace.style/components/dropdown
  • https://shoelace.style/components/select
  • https://shoelace.style/components/menu
  • https://shoelace.style/components/dialog

silverwind avatar Mar 31 '24 11:03 silverwind

@wxiaoguang maybe you can review these components for their accessibility:

I think they work well

wxiaoguang avatar Mar 31 '24 12:03 wxiaoguang

I just tested these four components. All are easily accessible (from my perspective as an unimpaired user).

There might be one issue where I'm not quite sure how bad it is: The components lack any aria- attributes (besides aria-disabled="false" and role="…"). I don't know how much impaired users rely on these being explicitly present. As long as we only have text content within, my guess is it should be fine.

As such, here's my :+1: to adopt shoelace instead.

delvh avatar Mar 31 '24 12:03 delvh

Shoelace is currently being transferred to become a project of FontAwesome: https://www.kickstarter.com/projects/fontawesome/web-awesome/description

They stated that there will be a bunch of breaking changes for 3.0, maybe it does make sense to wait

denyskon avatar Apr 26 '24 13:04 denyskon

I'm skeptical, seen too many such takeovers go wrong. I guess we'll wait until it's clear which components will be part of their "pro" version.

Also I would like to avoid a FontAwesome dependency, we ripped that out of Gitea not too long ago 😆.

silverwind avatar Apr 26 '24 13:04 silverwind

There is a lot of information in https://www.kickstarter.com/projects/fontawesome/web-awesome/faqs

I'm sceptical too, but it doesn't seem like anything bad will happen to the existing project, just that new development will probably focus more on the pro version than the free one

denyskon avatar Apr 26 '24 14:04 denyskon

Seems okay. Basic components will remain in the free version and those are all we need. We definitely don't need things like data grid.

Of course we should remain on the lookout for other webcomponent-based frameworks, the lighter the better.

silverwind avatar Apr 26 '24 19:04 silverwind

Actually there are ways to implement dropdown and modal without JS, as soon as Gitea uses Tailwind you can check how it's done in daisyUI and use the similar approach in Gitea if it fits the need:

https://daisyui.com/components/dropdown/ https://daisyui.com/components/modal/

condemil avatar Aug 22 '24 09:08 condemil

there are ways to implement dropdown and modal without JS

Only the very simplest of dropdowns can. As soon as you need functionality like a search you are in JS land.

Edit: I guess "Dropdown" is a convoluted term. If it just means floating content, then I can recommend either tippy.js or its successor floating-ui which both allow very sophisticated placement of floating content.

silverwind avatar Aug 22 '24 15:08 silverwind

Search could be done with htmx

condemil avatar Aug 23 '24 03:08 condemil

If you are looking at Web Components which is the most future proof approach that is lightweight, stay the hell away from Shoelace, or any component library that relies on or includes build steps for nonsense like TypeScript.

surfinky avatar Oct 25 '24 07:10 surfinky

https://www.radix-ui.com/primitives https://ui.shadcn.com/ https://headlessui.com/

sao-coding avatar Dec 14 '24 05:12 sao-coding

@silverwind has there been any further push for this? As I have been debugging https://github.com/go-gitea/gitea/issues/33532 and understanding it better it seems like using web components would always ensure event listeners are correctly attached.

Is would propose that we consider using VueJS for the web components since we already have it and it would allow us to use the same logic both in "vue land" and externally as web components.

McRaeAlex avatar Feb 20 '25 21:02 McRaeAlex

No further progress on this, but at least Fomantic needs to go eventually, e.g. the dropdowns mostly.

As for Vue vs. Webcomponents: Yes we can keep using Vue, but one major advantage of Webcomponents is they block the browser rendering, e.g. they render correct on the first browser paint. Vue components need to wait until the browser has fully parsed and executed the JS, so they "pop in". You can easily notice this problem when hitting F5 a few times.

So imho, Vue is only good for content that is shown on user interaction, e.g. stuff that is not part of the initial page rendering.

silverwind avatar Feb 21 '25 00:02 silverwind

Apologies, I should have been clearer about what I was proposing.

I meant that we use Vue to create our own web components. Below is a vue component I use internally (at allspice) for our dropdowns.

<template>
  <div
    ref="dropdownRef" @click="toggleDropdown"
    class="tw-text-[0.85rem] tw-pr-5 tw-inline-flex tw-items-center tw-gap-[0.25rem] tw-align-middle tw-min-w-0 tw-bg-button tw-cursor-pointer tw-whitespace-nowrap tw-border tw-border-light-border tw-rounded-[0.28rem] tw-h-[30px] tw-px-3 hover:tw-bg-hover hover:tw-text-text hover:tw-border-secondary-dark-2 tw-relative tw-font-normal"
  >
    <slot name="btn"/>
    <svg
      viewBox="0 0 16 16" ref="dropdownIcon" class="octicon-triangle-down tw-absolute tw-right-[0.5em]"
      width="14" height="14" aria-hidden="true"
    >
      <path
        d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427z"
      />
    </svg>
    <div v-show="isOpen" class="tw-absolute tw-left-0 tw-top-full tw-overflow-y-scroll tw-overflow-x-hidden tw-w-auto tw-min-w-full tw-max-h-[20rem] tw-shadow tw-z-10 tw-bg-menu tw-rounded-sm tw-border tw-border-secondary">
      <slot name="menu"/>
    </div>
  </div>
</template>

<script setup>
import {ref, onMounted, onUnmounted} from 'vue';

const dropdownRef = ref(null);
const isOpen = ref(false);

function toggleDropdown() {
  isOpen.value = !isOpen.value;
}

const handleClickOutside = (event) => {
  if (dropdownRef.value && !dropdownRef.value.contains(event.target)) {
    isOpen.value = false;
  }
};

onMounted(() => {
  document.addEventListener('click', handleClickOutside);
});

onUnmounted(() => {
  document.removeEventListener('click', handleClickOutside);
});
</script>

Using defineCustomElement we could do something for dropdowns more generally.

To accommodate different styles and behaviours, we could introduce 'variants' similar to how shadcn handles them.

McRaeAlex avatar Feb 24 '25 22:02 McRaeAlex

Ah, I wasn't aware that Vue components can render as custom elements. This could possibly be useful to avoid "pop in" if those components are then loaded in the webcomponents webpack chunk (https://github.com/go-gitea/gitea/blob/38ccc8e3e48e9b15f175287c0721ce0ff9892e5a/webpack.config.js#L86).

As for general components like dropdowns, I think it would still be a better choice to source them from a library than to code them ourselves, assuming said library is flexible enough.

silverwind avatar Feb 25 '25 11:02 silverwind

https://github.com/floating-ui/floating-ui is a low-level library for floating elements and it could be used to replace both our tippy.js usage as well as the fomantic dropdowns.

It's definitely not as high-level as something like shoelace, but I think it might just be suitable given that we prefer such flexible low-level approaches.

Specifically, we want to use the @floating-ui/dom package, e.g. not tied to any framework.

silverwind avatar Mar 14 '25 10:03 silverwind

I just stumbled over https://lion.js.org/, it's developed by ING (the bank). Seems very lightweight and they say in their readme that their focus is in providing as little styling as possible per default. Might be an option...

denyskon avatar Jun 14 '25 08:06 denyskon