supabase / ui

Supabase UI Library
ui-storybook-pre-release.vercel.app
MIT License
1.57k stars 152 forks source link

feature: Customization #17

Closed MildTomato closed 2 years ago

MildTomato commented 3 years ago

Feature request

Ability to customize / style each component

How it works now

it doesn't work at all, all the color variables are stuck in the ui lib and cannot be changed externally. all colors are set as rgb() values, also resulting in overriding externally as a tedious job.

If someone wanted to implement a 'brand color' change, they would need to target with CSS every class name that would contain the brand color, and then overwrite it, and for every shade color. This isn't practical.

Proposal

! this would be a breaking change !

All color variables are stored in css variables (CSS custom properties).

With css variables, we can set the variable names inside tailwind config file, rather than hex color values.

All of our components, when exported, would have colors set like this:

.sbui-btn {
   background-color: '--color-brand-700'
}

in the target app, using the ui library, you would need a stylesheet, that's imported into all pages, that contains all the variables, like:

.root,
#root,
#docs-root {
  --color-brand-100: #367ee9;
  --color-brand-200: #a0aec0;
  --color-brand-300: #718096;
/* and so on */

This will then show the correct colors in your app, which can be modified and changed to whatever you like.

it would (maybe) then be possible to just load up the correct variables file, depending on which 'theme' you wanted to show. (think slack themes)

downsides

css variables still isn't fully supported by all browsers

there is no support for ie

Screenshot 2021-01-12 at 10 27 02

this presents a problem, because if the css variables do not work, there is no fallback style -unless, we implement a fall back color for every variable, in every place it is used, in every component - this isn't a realistic solution really, and it would add a lot of redundant css.

dragos199993 commented 3 years ago

So the variables will be used like this after defined, right? module.exports = { theme: { extend: { colors: { primary-color: "var(--primary-color)", secondary-color: "var(--secondary-color)" }, }, }, };

My question is, how can the user, after is installing @supabase/ui, customise the styling?

I guess it will work if those variables are overwritten at project level. Maybe we can have the default ones which are currently defined now, move them in css variables and when the user is defining others at project level, those will be used. That means the change will not be a breaking change.

angelmtztrc commented 3 years ago

I don't if is the best way, but I was watching the way that @windmill/react-ui handles the theming, they have a themes/default.ts file that store an object with all of the names of the components and their styles (defaults, danger, info, etc). Then, they define a ThemeContext that will export the object globally in the application. After that, the components will extract their corresponding styles.

theme/default.ts

export default {
  alert: {
    base: 'text-4xl px-4 py-2',
  },
};

context/ThemeContext.tsx

import React from 'react';
import defaultTheme from '../themes/default';

interface ThemeContextInterface {
  theme: any;
  mode?: Mode;
  toggleMode?: any;
}

export const ThemeContext = React.createContext<ThemeContextInterface>({
  theme: defaultTheme,
});

interface ThemeProviderProps {
  children: React.ReactNode;
  value?: any;
}

export const ThemeProvider: React.FC<ThemeProviderProps> = ({
  children,
  value,
}) => {
  return (
    <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
  );
};

components/Alert.tsx

const Alert = () => {
  const { theme: { alert } } = useContext(ThemeContext)

  // ...
}

Maybe we don't need to handle all of the styles here (because we have a *.module.css) but we can use this approach to handle the background, text-color, border-color of the components.

MildTomato commented 3 years ago

@angelmtztrc yep, i think that's a good suggestion.

I think the only caveat of using a theme provider is you end up with a lot of consumers around every component - but it's also how AntDesign seem to apply theming as well and it looks convenient if someone wanted to swap the theme on the fly in the app.

I'm not against moving away from css modules either (or changing how they work), they're actually causing a problem on nextjs sites that are sever side rendered. Although that's a separate issue really.

I hadn't seen @windmill/react-ui before 🙈 i love the concept though.

I think, this solution does mean whoever uses SupabaseUI will need to have tailwind installed, as the css needs to get purged in the target app - I'm also not apposed to this, as everyone likes tailwind and this library is becoming more of a conveniently ready styled Radix/HeadlessUI components collection.

@angelmtztrc maybe one of us can try this out, we could try a POC with just 1 or 2 of the components ?

We could also use the same config setup windmill uses, by wrapping the tailwind config with a supabaseui config. https://windmillui.com/react-ui/installation#add-to-tailwind config file it imports -> https://github.com/estevanmaito/windmill-react-ui/blob/master/config.js

If anyone else has any suggestions, ideas or concerns please add them on here 👍

jonthomp commented 3 years ago

I would be a fan of the custom properties approach. Re browser support, we're already using tailwind which uses them so the risk is already present. A concern I might have around the context approach is centralising all the styles in one place, I like to have them as close to the related code as possible.

angelmtztrc commented 3 years ago

@MildTomato I can start by creating the custom wrapper for the tailwind.config.js file if you have no problem with that

MildTomato commented 3 years ago

@angelmtztrc go for it!

I think @jonthomp has a point, in this library, we should possibly still try and keep styles locally to each component, but the custom wrapper just allows for those styles to be overwritten. (Did i understand that correctly?). Although I would still like to see global variables, like brand color etc.

I do also like the idea of just using custom properties, which also means whoever is using this library doesn't need to have tailwind installed, so one less dependency / tool to learn.

The counter argument though is if we rely on tailwind for everything, we could eliminate css being exported from the library and all the css is neatly purged in the target app instead (this is probably a really great fit for the Supabase dashboard), this also possibly reduces some duplicated css. For example, if 'flex' is used in the Supabase UI or the dashboard app, we'll just have one .flex class - as apposed to today, we have quite a few css classes that just add the same functionality as flex.

This is quite a large deviation for this library though, but I could see this being useful even though it essentially forces you to use tailwind.

I think the first decision here for us is, would people like to see a tailwind based library, that requires tailwind to use, or would you rather have/work on a ui library that has pre baked styles, that has no dependency, that can be customised with a theme file (or something like that).

Feel free to keep this thread going, would be great to hear what everyone thinks.

MildTomato commented 3 years ago

I've started a POC for this based on @angelmtztrc's suggestion https://github.com/supabase/ui/pull/241

jonas-kgomo commented 3 years ago

Is there currently a temporary fix for this?

MildTomato commented 3 years ago

I'm afraid not, will try and get this done this week though

chekdotdev commented 2 years ago

How have things progressed on theming? @MildTomato thank you for all you're doing 🙏

MildTomato commented 2 years ago

As you can see, it was not 1 week. 😬

I am working on this right now though.

I'm currently refactoring some more components away from CSS modules but I'm getting there.

Main changes

In short, though, a lot of components are using Radix primitives, and there is a react theme provider that inserts either default tailwind CSS classes, or you can override the theme with your own one. (You could even just use non-tailwind classes I guess, or use stitches in this custom theme).

There is a tailwind config wrapper that you wrap around your own tailwind config that will add any necessary plugins/extends needed for the default theme.

We're using Radix colors rather than Tailwind colors for the default theme.

We're also using a standard color scale of gray across almost everything, but the idea is that you could replace this scale with whatever color scale you like. So it could be a warm gray, cool gray, slate.. etc. These can be used as CSS variables which are pretty handy as you could swap out the scale easily for light/dark/multiple themes.

One of the major headaches is that the Brand color is also based on a scale, which is annoying since someone would have to make the scale of their brand color for this to be useful.

I tried just using 1 hex color for the brand, and an accent, but it was just always really hard and always restrictive; it made a lot more sense to just have a brand color scale - made it a lot easier to work with.

Breaking changes

Components being removed

I'm also going to drop a few components as they are a pain to work with, don't really solve anything, and add bloat to the library. It's also just a lot easier to just use tailwind in your app for these. The following will be deprecated.

Things I've improved

chekdotdev commented 2 years ago

Wow, awesome! Thanks for the reply. I'd offer to help, but Radix is new to me so I'd likely just slow things down.

For now, we're doing this:

/* override supabase ui */

.sbui-formlayout__label,
.sbui-typography-text  {
    color: unset !important; /* to be replaced with branded color */
}

That along with the style prop inside of <Auth/> gives us all we need to customize manually.

Quite honestly, an unstyled prop would be pretty nice to be able to use Auth and the parent wrapper without any styles.

MildTomato commented 2 years ago

@jchekanoff are you just using <Auth/> ?

MildTomato commented 2 years ago

Quite honestly, an unstyled prop would be pretty nice to be able to use Auth and the parent wrapper without any styles.

Sounds like a good idea.

chekdotdev commented 2 years ago

@MildTomato Sorry I missed this -- Yes! Just using <Auth/>.

MildTomato commented 2 years ago

@jchekanoff ok! - I'm starting a new repo for the Auth component. I think we're going to drop support for it in this library as it will need its own theming/customization solution and I don't want to force anyone to install a whole UI library just to use the Auth component.

I'll make sure that the new package (probably called @supabase/auth-elements-react) will be working before I remove it from here.

chekdotdev commented 2 years ago

Awesome! I won't work on a PR for this repo, then :smile:

Tag me in on supabse/auth-elements#4 if I can contribute there.

sicktastic commented 2 years ago

Is there a way to create your theme? At this point, I just want to update the button colors to our branding.

MildTomato commented 2 years ago

Auth component has moved to supabase-community/auth-ui

We released this last week. https://github.com/supabase-community/auth-ui

Some docs on customizing. https://supabase.com/docs/guides/auth/auth-helpers/auth-ui#customization for overriding the button color, do something like this

sicktastic commented 2 years ago

Thanks @MildTomato, that worked!

MildTomato commented 2 years ago

Supabase UI is moving.

We are moving the components to the main mono repo at github.com/supabase/supabase.

I encourage anyone who would like to see theming implemented in the supabase dashboard/studio to make a new discussion in the main mono repo.

https://github.com/supabase/supabase/discussions/new?category=ideas