Closed go4cas closed 4 years ago
Good questions that require a long answer since there are lots of ways to skin these cats.
External libraries come in different shapes and sizes. Some are component libraries written in Vue, some are semantic css classes you need to adhere to (bootstrap), some are just collections of presentational classes (tailwind). Here are some solutions:
Custom elements (ideal):
The goal of Vue Formulate has been and will continue to be a simple, unified API when composing forms (single input component). Other solutions, like scoped slots dont always lend themselves to this unified API. In otherwords you would need to wrap a scoped slot implementation in another component so instead of using <FormulateInput>
for every element, ones you wrap would be <AntTextField>
or anything you chose to name it...and generally with different props. This is a bit antithetical to the developer experience Vue Formulate is trying to provide.
So, Vue Formulate tackles this challenge by allowing you to extend the library of types
and then canonize those into a plugin. This is available today. I would absolutely love for some community member to come up with the ant-design
plugin, the buefy
plugin, or the vux
plugin etc. This would allow for everyone to keep using single element <FormulateInput>
to compose forms, but also leverage some of the great features of Vue Formulate.
import VueFormulate from '@braid/vue-formulate'
import VueFormulateAntDesign from '@your/vue-formulate-ant-design'
Vue.use(VueFormualte, {
plugins: [ VueFormulateAntDesign ]
})
...
<FormulateInput
type="ant-checkbox"
/>
This is the goal for where Vue Formulate is heading, but admitedly I need some community developers to help write some plugins to get it there.
Scoped slots (soon):
What’s most commonly used to solve this problem is scoped slots. This is already mostly supported but not currently a public API or documented — but its on the roadmap (#34) for the 2.3.0 release. If you'd like to leverage it, checkout the context
object, and the scoped slots already in use on FormulateInput
. Again, this isn't directly in line with Vue Formulate’s goals, but sometimes it's just a necessity for a fields on a project.
Class lists functions (2.4.0?): There still some libraries that are just class driven (tailwind, bootstrap, etc). This is currently not well solved, but the current working strategy for how to bring support is by implementing class list functions that would allow that kinda of flexibility. This is still a roadmap feature. In the meantime users of these frameworks will have to extend their base classes in css.
This is a hugely needed feature, and something I wanted to get out in 2.2.0. It is technically possible right now using a v-for
itterator on a FormulateInput
, but the field values dont collapse into a nice api. The API will be:
<FormulateInput
name="people"
type="group"
limit="3"
>
<FormulateInput
type="text"
name="name"
/>
<FormulateInput
name="birthday"
type="date"
/>
</FormulateInput>
The above would produce a repeating group of fields with an + Add button (overridable with a scoped slot), and the model results would collect as an array:
{
people: [
{ name: 'Tom', birthday: '12/12/1980' },
...
]
}
How does that API sound right to you @go4cas?
@justin-schroeder ... first off, thanks for taking the time to work through my questions! It's great to see authors of open source libraries still putting thought into their designs!
Your comments on "Theming" actually made me relook at your docs, specifically the section on Custom Inputs. Surely I could do something similar to your auto-complete component example, but instead of using a normal <input>
inside the <template>
, I could use the <a-input>
(from the vue ant-design lib)? Or, using a css library (e.g. Tailwind) just style the <input>
with tailwind classes inside the <template>
? Would these use cases work?
Then, in terms of "Field Groups", I may not have explained my requirement correctly. I am not looking at repeatable groups of similar components, but rather having the ability to group certain components together in a "section" on the form. This is useful when you have forms with a large number of components, and having them in related sections, increases usability. What do you think?
@go4cas Yes, you can definitely implement what you're wanting to do with Custom Inputs. If you want to roll up many/most of ant-design's fields into a plugin I would be highly supportive :)
I definitely did misinterpret the field groups question. Vue Formulate does not aim to be a layout tool, but you do have the freedom to place FormulateInput
elements at any depth under a FormulateForm
element, so for accessibility reasons I would suggest using a fieldset + legend + some css. Here's an example I threw into codepen:
https://codepen.io/justin-schroeder/pen/ExjRdRZ
Let me know if that doesn't fully answer your question, or if you'd like any help building a published ant design plugin :)
Hey @justin-schroeder,
Do you have a rough eta on the 2.3.0 release?
I've only just come across your library and it's fantastic! I'm a heavy Tailwind user though so I'd like better access to the elements via scoped slots so I can create markup similar to this...
<div>
<label for="email" class="block text-sm font-medium leading-5 text-gray-700">Email</label>
<div class="mt-1 relative rounded-md shadow-sm">
<input id="email" class="form-input block w-full sm:text-sm sm:leading-5" placeholder="you@example.com" />
</div>
</div>
I've tried targeting the elements via the data-classification
attributes but unfortunately I need to add the form-input
class to input as it's part of a Tailwind plugin and doesn't work with Tailwind's @apply
method.
I'm happy to try this now with 2.2.8
if you think it's possible?
Thanks
@gilesbutler ha! I've been wondering when the first tailwind user would start asking questions :). Honestly, I wanted to get v2.3.0
out last weekend. Timelines are hard with software, but I've learned they're even harder with OSS. The good news is progress is still being made on this daily, and the scoped slot portion is already done and working on a feature branch (feature/scoped-slots) that will get merged into release/2.3.0
. The first pass at docs are written as well https://vueformulatecom-git-release-230.braid.now.sh/guide/inputs/slots/.
That structure might might change a bit between now and release, but not much, and it gives you pretty much full scoped slot capability.
Now, that said, I've done a lot of thinking about how this package should handle "you people 😉" who are super gung-ho about tailwind or other class-happy ui frameworks, and I think the ideal situation would be to have maps of classes that can be overwritten globally, by classification, or per input. The default would be something like:
function classMap(context) {
return {
"outer": `formulate-input`,
"outer-wrapper": `formulate-input-wrapper`,
"element-wrapper": `formulate-input-element formulate-input-element--${type}`
"element": '',
"help": "formulate-input-help",
"errors": "formulate-input-errors",
"error": "formulate-input-error"
}
}
The idea is that classMap function would be defined globally for all inputs, and then each sub-type could override it, and then as granular as individual input fields could also override each:
<FormulateInput
type="text"
classmap-element="form-input block w-full sm:text-sm sm:leading-5"
/>
@gilesbutler I've created a new proposal for this: https://github.com/wearebraid/vue-formulate/issues/66
I'd love to get feedback from you or anyone else in the Tailwind community if this would be a good way to handle authoring these components for tailwind.
Haha thanks for the awesome response @justin-schroeder!
I've been wondering when the first tailwind user would start asking questions :) I'm honoured to be the first ha! Also my people appreciate the future forethought for our beloved css utility frameworks 🤴
I read through your updated docs for scoped slots, makes perfect sense. I completely understand your goals and objectives for the library. Personally I think scoped slots are the way to go as an advanced use case as I feel like they're widely accepted as that in the Vue community as well.
I'll respond in #66 with proposal feedback. I'll also post it in the Tailwind Discord to see if we can drive some more feedback from the community 👍
Congratulations on the 2.3.0 release @justin-schroeder - looking forward to trying it out over the next few days 🙌
Thanks @gilesbutler! Classmaps are not in this release yet, but scoped slots are 👍 hope those fulfill you needs short term!
Awesome thanks @justin-schroeder.
I've just found an issue with field groups. Will run it by you here first but happy to open an issue too if need be.
Given the following code...
<FormulateInput type="group" name="landlord">
<FormulateInput
v-if="company.abn"
type="text"
name="abn"
:value="company.abn"
/>
<FormulateInput
v-if="company.name"
type="text"
name="name"
:value="company.name"
/>
<FormulateInput
v-if="company.organizationId"
type="text"
name="organizationId"
:value="company.organizationId"
/>
</FormulateInput>
company
is an empty object to start with. When I set it's props all the fields update with the correct values. Am I doing something wrong or is this a bug?
@gilesbutler What you're doing is not at all outside the scope of groups, but I think there are a few things at play here:
value
prop sounds like its doing what is intended — setting the initial value, but not updating after the fact. Use v-model
to allow reactive manipulation.v-if
on your fields is really what you want. If you had maintained reactivity (ie using v-model
instead of :value
) then your fields would have disappeared when you deleted the last character in each field, is that intended?value
or v-model
on the group input itself (much like a form). Just remember it expects an array!Here's an example using your code and a v-model on the group
:
https://codepen.io/justin-schroeder/pen/PoPxyLx
And if you really need the data without the array wrapper, I'd recommend just using a computed property.
Is this helpful?
🤦♂️ Sorry @justin-schroeder I was using :value
instead of v-model
! You're right that is the correct behaviour. Adding v-model
fixed things and yes very helpful thanks.
I realised the example I posted was actually using text
inputs (for debugging) as opposed to hidden
inputs which is what we're actually aiming for...
<FormulateInput
v-model="company.abn"
type="hidden"
name="abn"
/>
The reason we're doing this is because we have a FormulateInput
that is wrapped in a renderless component that passes down methods and data via scoped slots. It takes a company business number as input which we then search for using an async request in the renderless component (exposed via a scoped slot prop). Some of the resulting data needs to be displayed and other bits don't, but they do need to be submitted with the form hence they're added to the hidden fields.
We're doing it this way as the company business search needs to be reused across multiple components so renderless and scoped slots seemed the best way to go. Not sure if it's the best way to but seems to be working ok.
Thanks for your help 👍
unfortunately I need to add the form-input class to input as it's part of a Tailwind plugin and doesn't work with Tailwind's @apply method.
Oh man! I just lost ~3 hours trying to figure a solution for that. ☹️
It's my first time using Tailwind (coming from Bulma) and I am still confused about PostCSS, PurgeCSS, etc. Currently using Nuxt + SCSS + Tailwind module + Tailwind UI, so it's even worse to understand what is going on under the hood.
The official suggestion is to use @extend .form-input;
but with my setup I have failed multiple times.
@gilesbutler If you are not using Scss maybe this can help: https://github.com/tailwindcss/custom-forms/issues/12#issuecomment-496001713
Did you achieve an workaround for now?
Hey @hmaesta,
Thanks for that, yep you can use scoped slots in the 2.3.0 release.
I worked through the documentation, and I have the following questions (in case I've missed something in the docs):
Field Groups: Is there an option to group fields together on a form? E.g. on a user profile form having a section for person details (fields for name, last name, etc), a section for profile (fields for user name, avatar image), section with contact details (fields for phone, email, etc)
Theming: the theming section in the docs mention that you can style the field elements using SCSS variables. Is it possible to use components from another UI library, e.g. Vue Ant Design?