Open sowka1995 opened 2 months ago
I've never used shadcn before, but for tailwind you can add the utility classes to each component with the controlClassnames
prop: https://react-querybuilder.js.org/docs/components/querybuilder#controlclassnames
I don't have an example specifically for tailwind but the Tremor example uses tailwind internally: https://github.com/react-querybuilder/react-querybuilder/tree/main/examples/tremor
I was going to close this but I think I'll keep it open as a request for a pure Tailwind example.
I'm trying to implement this, still very rough but I'll share progress and code.
Implementing a real theme might not work since shadcn/ui is based on copying/pasting components, so there's no way to import those as you would in a classic UI library.
shadcn/ui is based on copying/pasting components
Yeah, when I was looking into it I couldn't figure out how that was a benefit. That said, you could theoretically replace all the components with custom components. A lot of the default logic is in hooks so it might not actually be a huge amount of work.
Well that's the selling point of shadcn/ui, you own the ui library, so customizing it is as easy as editing files directly.
It has its upsides and downsides, but for example if I wanted to customize @react-querybuilder/chakra, I would have to fork it or override classes, which may not cover all my needs.
On the other hand, with creating a react-querybuilder-shadcn-ui component, since I would import ui components from my own codebase, it will use my very own ui components that are already custom.
Not everyone likes it, but it's a cool approach.
That said, making a react-querybuilder-shadcn-ui library would imply making copy-pastable code instead of a npm module, which is what I'm planning to do and share.
Another approach would be using dependency injection to inject custom components, but it would be overwhelming.
I'm trying to implement this, still very rough but I'll share progress and code.
Implementing a real theme might not work since shadcn/ui is based on copying/pasting components, so there's no way to import those as you would in a classic UI library.
It looks really awesome even at this point! :heart_eyes:
you own the ui library, so customizing it is as easy as editing files directly.
For what it's worth, I'm not knocking this approach. I guess I don't understand the difference between copy/pasting code and forking a library. You lose the upgrade path either way, and while I can see the benefits of "owning" your components, you're also taking on responsibility for compatibility, testing, etc.
if I wanted to customize @react-querybuilder/chakra, I would have to fork it or override classes
This is not correct. You can copy/paste the components from the @react-querybuilder/chakra
source and use them independently of the package itself. You can also implement the package as recommended but override certain components with modified versions using the controlElements
prop. (I'm not exactly sure what you mean by "override classes," but if I understand correctly that would not be necessary.)
making a react-querybuilder-shadcn-ui library would imply making copy-pastable code instead of a npm module
I would be happy to add something like this to the examples folder, foregoing an npm package. Feel free to submit a PR to that effect!
Another approach would be using dependency injection to inject custom components, but it would be overwhelming.
Again, controlElements
allows you to replace any component with your own implementation--no fancy DI or anything like that. We even have documentation on falling back to the default components if your custom implementation only has to cover certain cases. And if you only need to modify styles, controlClassnames
can add custom CSS classes to each component (or you can apply styles to the standard classes).
For what it's worth, I'm not knocking this approach. I guess I don't understand the difference between copy/pasting code and forking a library. You lose the upgrade path either way, and while I can see the benefits of "owning" your components, you're also taking on responsibility for compatibility, testing, etc.
Honestly this is a whole debate by itself, and I can totally understand it's not obvious, but after years using Chakra and fighting it to customize components (in particular the theming API is complex with components made of multiple parts) VS editing shadcn/ui components by hand in my components folder I'm sold, but I was very skeptical at first.
And forking Chakra is a lot more effort than copy pasting some JSX.
This is not correct. You can copy/paste the components from the @react-querybuilder/chakra source and use them independently of the package itself. You can also implement the package as recommended but override certain components with modified versions using the controlElements prop. (I'm not exactly sure what you mean by "override classes," but if I understand correctly that would not be necessary.)
Yes of course, but what I meant is that in the end if you want to customize freely and use your very own components you end up copy pasting basically :) Which is kind of the point of the copy-pasting approach of shadcn/ui.
I would be happy to add something like this to the examples folder, foregoing an npm package. Feel free to submit a PR to that effect!
I will !
Again, controlElements allows you to replace any component with your own implementation--no fancy DI or anything like that. We even have documentation on falling back to the default components if your custom implementation only has to cover certain cases. And if you only need to modify styles, controlClassnames can add custom CSS classes to each component (or you can apply styles to the standard classes).
What I meant is that to publish a module that would allow using your own shadcn/ui components, since the paths are local to your project, it's impossible to reference them from the module code.
after years using Chakra and fighting it to customize components
I feel your pain with Chakra. I nearly gave up on building that compatibility package several times. Chakra and Ant Design have been the most painful so far, although MUI also took a long time to get right because of the way they handle the context provider.
What I meant is that to publish a module that would allow using your own shadcn/ui components, since the paths are local to your project, it's impossible to reference them from the module code.
Ok I think I understand now. You're saying that it doesn't make sense to publish a compatibility package for shadcn à la @react-querybuilder/chakra
or @react-querybuilder/antd
because it wouldn't be able to reference anything specific to shadcn, all of the shadcn-based code being local to the consuming project. At first I thought you were saying you'd have to fork RQB in order to use (copy/pasted) shadcn components.
For what it's worth—and for future reference, I guess—here's an example using the shadcn Button
component for all the buttons in RQB. This is based on the Button
example in the shadcn docs and the actual ActionElement
code from RQB:
import { Button } from "@/components/ui/button";
const MyActionElement = (props: ActionPropsWithRulesAndAdders) => (
<Button
type="button"
className={props.className}
title={props.disabledTranslation && disabled ? props.disabledTranslation.title : props.title}
disabled={props.disabled && !props.disabledTranslation}
onClick={e => props.handleOnClick(e)}
>
{props.disabledTranslation && props.disabled ? props.disabledTranslation.label : props.label}
</Button>
);
export const App = () => {
return <QueryBuilder controlElements={{ actionElement: MyActionElement }} />
}
(controlElements#actionElement
is new in RQB v7.)
Ok I think I understand now. You're saying that it doesn't make sense to publish a compatibility package for shadcn à la @react-querybuilder/chakra or @react-querybuilder/antd because it wouldn't be able to reference anything specific to shadcn, all of the shadcn-based code being local to the consuming project. At first I thought you were saying you'd have to fork RQB in order to use (copy/pasted) shadcn components.
Absolutely !
For what it's worth—and for future reference, I guess—here's an example using the shadcn Button component for all the buttons in RQB. This is based on the Button example in the shadcn docs and the actual ActionElement code from RQB:
That's pretty much what I did, although I used different variations for addRule, addGroup etc.
Do you already have a working example you could share? I need it and I don't know whether to start implementing Shadcn integration from scratch.
Do you already have a working example you could share? I need it and I don't know whether to start implementing Shadcn integration from scratch.
Unless @jide has created something, my example in https://github.com/react-querybuilder/react-querybuilder/issues/672#issuecomment-2019118003 is all we have for now.
The problem with Shadcn is there is you can't really do "integration." Since components are local to each project and not common to all Shadcn implementations, you'd have to reimplement RQB components using your own Shadcn components.
You shouldn't have to reimplement QueryBuilder
, RuleGroup
, or Rule
, but you would need to reimplement ActionElement
, ValueSelector
, and ValueEditor
(and, depending on your configuration, DragHandle
, NotToggle
, and ShiftActions
). The most complex of those is ValueEditor
; the others are relatively simple.
Hey,
I took the time to extract the ui into a clean project. Here it is : https://github.com/jide/react-querybuilder-shadcn-ui/tree/main/src/components/react-querybuilder-shadcn-ui
It's still very rough, but I thought it may be useful at this stage.
Added more UI. Starts to look decent IMO !
Added more UI. Starts to look decent IMO !
It looks Impressive! I will try to use it in my project when I return from my vacation.
Forgot to mention I also added dark mode support. Still some work to do on drag n drop and shift features, but its functional.
In the end, I think my "component injection" idea may not be that bad... It's not fun to copy and paste all the files manually without a CLI tool like shadcn/ui has. Yes, I know 🙃
This way, it will be distributable as a standalone npm module while still allowing using shadcn/ui components from your project.
This is how the implementation looks like :
import { getQueryBuilderShadcnUi } from "@react-querybuilder/shadcn-ui";
// Import needed shadcn/ui components.
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Textarea } from "@/components/ui/textarea";
import {
Select,
SelectContent,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
// Pass them to getQueryBuilderShadcnUi()
const components = {
Button,
Switch,
Checkbox,
Input,
Label,
RadioGroup,
RadioGroupItem,
Textarea,
Select,
SelectContent,
SelectTrigger,
SelectValue,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
};
const QueryBuilderShadcnUi = getQueryBuilderShadcnUi(components);
@jakeboone02 What do you think of this approach ?
@jide this is looking really great. Kudos!
After looking at the code in full, I'm going to politely rescind my offer to host the example code in the /examples
folder of this repo. The reason is purely to avoid the maintenance burden. Naturally I would feel obligated to keep the example working and up to date with the latest react-querybuilder
version, but since so much of its code would be copy-pasted straight from the original source, it would effectively double the effort required for any component code changes.
However, I would be more than happy to link to this example from somewhere in the repo or the website. It's coming together as a great showcase of the modularity of RQB. My only condition would be that the example repo makes clear what RQB version the component code was copied from, in addition to a pinned react-querybuilder
patch version in package.json
(no leading caret/tilde/etc).
...I was just about to submit that when your last comment came through. The method you've proposed is similar to what we do with MUI components in @react-querybuilder/material
. The documentation here might give you some more ideas. It would be good to explore that further.
Damn, how did not I see this from the mui package.
Indeed that's the same approach. I'm willing to submit a PR, if you feel comfortable with the maintenance overhead. Otherwise I'll make a separate contrib npm package which is fine too.
Let me know.
Do a PR and we'll see where it goes.
Description of the feature
Are there any plans to add a new theme based on the growing popularity of shadcn or pure Tailwind?
Maybe someone already has a demo?