I have written many times my struggles on here that web UI is a huge gap and undermines Phoenix as a viable way to build apps fast. Phoenix isn’t fast vs other solutions which have established UI frameworks.
A set of semantic headless components that address accessibility is the missing piece in the ecosystem and now, with Doggo you have made great strides to closing that gap. Well done and thank-you for your efforts.
I’ve actually moved to using web components / custom elements because of this gap (Shoelace and Adobe Spectrum with the what looks to be amazing Spectrum 2 just around the corner).
IMO Doggo should be seriously considered by the Phoenix core team as a foundation library given there is nothing other than the “stop gap” core components which are not fit for purpose and create a maintenance issue for phoenix apps.
If Phoenix had a set of core semantic components which implement all the accessibility requirements correctly and cover the common application use cases then tools, generators, CSS frameworks, themes, application website templates, UI design/figma templates, and real storybook collaboration with design teams can thrive within the Phoenix ecosystem.
Without a core semantic UI component library Phoenix and liveview will remain a fringe hobby web technology with low adoption because the gap between UI design teams and dev teams is too large as they cant work effectively or efficiently together. Phoenix in effect slows you down vs just using react or next.js or any other popular solution that has established UI components and real storybook support out of the box to close the gap between design intent and devs.
Have you looked at bits-ui for inspiration in terms of structuring your headless UI components.
Bits-ui is a headless UI for accessibility concerns and is what shadcn-svelte is built on.
consider breaking things into module concerns
keep drawers generic in respect of content.
consider semantics for drawers like left, right, top, bottom and also scoped to another container element like Shoelace does as sometimes you don’t want a drawer to be viewport scope.
consider generic menu lists which can be used in drop down menus, pickers, drawers etc vs drawer specific menu items.
consider structuring your semantic UI along similar lines to Shoelace and Adobe Spectum given the relatively large coverage and use cases. Spectum React Aria provides a good example which only covers the accessibility /Aria concerns.
Thanks for the feedback! I put the items on my to-do list for further consideration. I wasn’t familiar with bits-ui, I’ll definitely check it out.
In general, the goal is to define sensible primitives while still allowing the user to add further customization. The drawer component for example has three slots, but it doesn’t make any assumptions about the content of those slots. You could just use the :top slot and put any content in there, you’re not bound to the other drawer_* components. To reflect top/right/bottom/left drawers, you can add your own modifier classes (just as an example, I might consider adding a separate attribute for this in particular).
Thanks for your start on this important step for the community.
I don’t pretend to be any kind of expert in this, only sharing things that struck me a well designed with good coverage.
I am kind of impressed with what Adobe is doing with Spectrum 2, I think the time of custom elements is now and they will be leading the pack with a solid approach and huge investment as they are betting the farm on it with over 100 apps to be migrated to their web components.
Despite being quite bullish on web components I see incredible value for a semantic UI contract in Phoenix.
My thoughts are that your library could in fact be the start of a completely renderless behaviour module and your current implementation could be just one rendition of the html. With the right abstraction it should be possible to back the semantic UI onto your current rendition, Shoelace, Adobe Spectrum or something else entirely, even a native UI.
That is actually something I was thinking about. I have another project in its very early stages. In its current form, it is only an SCSS starter kit, but the idea in general was to define a specification first (e.g. a naming convention for design tokens and recommendations for the project structure), with the starter kit basically just being a reference implementation. And since I’ve published Doggo, I was wondering whether it would make sense to define a collection of standard components in a generic way that is not bound to any frameworks or languages. If that component specification was comprehensive enough and in a machine-readable format (e.g. JSON), it would be possible to generate Phoenix components from that specification, indeed, at least the HEEx part.
@woylie nice job! Is it possible to maybe have the storybook deployed somewhere (Fly?) so folks can quickly see how the components work and behave? This would definitely reduce the friction to test and potentially adopt these components.
Also, are you currently using these components in a project or are you just developing them on their own?
I’m working for a few months on writing a headless components library for LV too, but the more the merrier as we are still pretty thin on that front. The idea is for it to be the base of a more opinionated / styled UI library that makes use of it.
Doggo 0.5.0 focuses on the semantics of the remaining APG patterns. Note that not all added components are fully functional yet: client-side interactivity including keyboard support will be the next focus. Components that are not ready to be used yet are marked with admonition blocks in the documentation.
New component: Doggo.alert_dialog/1.
New component: Doggo.carousel/1.
New component: Doggo.combobox/1.
New component: Doggo.disclosure_button/1.
New component: Doggo.menu/1.
New component: Doggo.menu_bar/1.
New component: Doggo.menu_button/1.
New component: Doggo.menu_group/1.
New component: Doggo.menu_item/1.
New component: Doggo.menu_item_checkbox/1.
New component: Doggo.menu_item_radio_group/1.
New component: Doggo.radio_group/1.
New component: Doggo.split_pane/1.
New component: Doggo.tabs/1.
New component: Doggo.toolbar/1.
New component: Doggo.tree/1.
Storybook page about modifier classes.
Mix task mix dog.modifiers to list all modifier classes.
Set aria-invalid and aria-errormessage attributes in Doggo.input/1
Use buttons instead of links in Doggo.action_bar/1.
Add toolbar role to Doggo.action_bar/1.
Use section instead of article in Doggo.modal/1.
Use button for close button in Doggo.modal/1.
Add dismissable attribute to Doggo.modal/1.
Remove role from button_link/1, add class.
Rename Doggo.drawer/1 slots to header, main, and footer.
Rename Doggo.drawer_nav/1, Doggo.drawer_nav_nested/1 and Doggo.drawer_nav_section to Doggo.vertical_nav/1, Doggo.vertical_nav_nested/1 and Doggo.vertical_nav_section/1.