Features:
- Every Mob component template in
priv/moblinks to its page on mishka.tools in its moduledoc (**Documentation:** https://mishka.tools/chelekom/docs/mob/<name>), like the styled components mix mishka.ui.gen.mobandmix mishka.ui.gen.mob.componentsdeclare the generated tags in the app's ownconfig :mob, :extra_tagsinstead of writing intodeps/mob/priv/tags/*.txt, whichmix deps.getdiscarded and Mob's docs say not to edit. Only missing tags are added to a~w()or plain list, the rest of the list is kept, andmix mishka.ui.uninstallremoves just the removed tags. Igniter 0.8.5- The CMS bundle says which attributes also take a class string. Where every helper an attribute
reaches ends in a
defp helper(params) when is_binary(params)catch-all —size,rounded,padding,space, mostvariants — the template drawssize="py-1 px-2"as readily assize="small", and the bundle now ships the named list as Phoenix's non-exhaustiveopts.examplesinstead of a closedopts.values, so a consumer that validates againstvaluesstops refusing it. 311 attributes shipexamples; an attribute this cannot read in full stays closed - The CMS bundle carries each attribute's own option list. A component's
args:config already enumerates whatvariant,color,size,roundedandpaddingaccept, and the exporter threw it away — a consumer had to recover the same lists from the<%= if %>gating around each helper clause, which is lossy (alert's fourteen colours came back as eleven). The list is now written onto the attribute asopts.values, whereattr :color, :string, values: [...]would have put it, and is skipped for the few attributes whose own default contradicts it (default: ""), because a bundle whose components cannot be compiled is worse than one that says less about them. 23 attributes carried a value list before; 364 do now - The CMS bundle carries each component's
doc_url, so a consumer can link to the page that explains the component it is offering - The daisyUI gallery paints all 92 headless components with daisyUI and Tailwind classes in the examples' own markup. Copying an example gives you the component and its look; there is no stylesheet to take with it. The design system itself stays your dependency
- A
*_classattribute for every part a component renders, so any part can be restyled from markup. This is what makes the class-only gallery possible, and it is enforced by a test that reads the components' own sources - Known divergence from the stylesheet it replaces: a few parts whose CSS declared
color: var(--color-base-content)no longer declare it, so under a darkdata-themethey inherit the surrounding colour instead of following the theme (sliderand its descendants,pagination's ellipsis). Painting it back is not the fix — the declaration used to lose to daisyUI's own colour modifiers (range-primaryand friends) from@layer components, and the same value written as a utility wins, flattening every coloured variant. Set the colour on your own container if you place these in a dark subtree - Add 17 headless components, taking the line from 75 to 92:
alert,breadcrumb,button,calendar,card,carousel,countdown,dock,fab,file_input,pagination,rating,stepper,table,text_input,textareaandtheme_controller - The headless
switchtakes:on_iconand:off_iconslots. Both render inside the track, after the thumb, and carrydata-checked/data-unchecked, so a skin can cross-fade them rather than swapping one element for another
Bug fixes:
The headless
chartkeeps its styling with--lib billboardunder a Content Security Policy that allows no inline style. The engine wrote billboard's stylesheet into a<style>element, which astyle-srcwithout'unsafe-inline'or a nonce refuses, so lines filled in black and the axes and tooltips lost their look. It now adds the same rules once per page as an adopted constructable stylesheet, which nostyle-srcgoverns, and adopts it again after a LiveView navigation only if the page dropped it. Its tooltip, unless the config names a template of its own, draws each series' swatch as an SVG circle filled through itsfillattribute instead of billboard'sstyleattribute.billboard: { injectStyles: false }inchart_extensions.jsstill turns both off; a browser without constructable stylesheets warns once and draws the charts unstyled. A test now fails on any hook in the library, or in the CMS kits, that writes a<style>element or astyleattributeThe headless
chartdraws with--lib billboard. A bundler resolvesbillboard.jsto its ESM build, which draws a chart type only after that type's module has been called, so every chart threw "Please, make sure if 'line' module has been imported" while mounting and the page's LiveView never connected. The engine now imports all twenty billboard type modules and replacesdata.typeand each value ofdata.typeswith its module's call; it also calls the grid module, and the zoom, subchart, data selection and regions modules when the config turns them on. The config keeps the string types the billboard docs show, and an unknown type warns once in the console and draws as a lineGenerated components lay out the same on every Elixir. 31 helper clauses (21 in 16 styled templates, among them
dock,blockquote,buttonandtable, and 10 in the headlesscard,chart,dock,sparklineandstepper) were writtendefp name(args) when guard, do: value. Once that outgrows a line, Elixir 1.18 putsdo:on a line of its own and 1.19 and later keep it after the guard, so a file generated on one failedmix format --check-formattedon the other. They are written withdo ... end, which every version lays out alike, andTemplateFormatStabilityTestfails on a new guard clause that takesdo:and does not fit on one lineThe buttons in the demos and the usage rules show the pointer: 213 examples across
priv/demosandusage-rules(the table, clipboard, collapse, navbar and dropdown demos, the component, headless and hook rules) namecursor-pointer, so what a reader copies keeps the cursor v3's preflight gave it.TailwindV4ClassesTestreads them as it reads the templatesThe development showcase's own buttons show the pointer too: the alert preview's dismiss button, a button a page puts in a component's slot, the form-demo submit buttons and the rest — 101 of them. The templates' pointer test never saw them, since they are page markup, so a second test reads the pages. And the sidebar preview can be closed: it held
translate-none!on its root, which the close command, removingtranslate-none, cannot take away; a test now holds the classeshide_sidebar,show_sidebar,hide_drawerandshow_draweradd and remove against the roots they are rendered on and against the previewsButtons keep the pointer cursor. Tailwind v3's preflight set
cursor: pointeronbuttonand[role=button]; v4's does not, so every clickable the templates render showed the arrow. Each of them carriescursor-pointeritself now: 31 elements acrossalert,badge,banner,carousel(arrows and indicators),clipboard,collapse,combobox(trigger and clear button),dock,drawer,file_field,gallery(filters),mega_menu,modal,password_field,search_field,sidebar,speed_dialandtoast, plus the flashalert, which dismisses on click, and the trigger of aclickablepopover. Thecollapsetrigger also sets it on abuttoninside, which the arrow would otherwise reach through the wrapper. The examples in the component docs use it on their buttons too. The clipboard and collapsible hooks add the class to an element they markrole=button.TailwindV4ClassesTestfails on abuttonorrole=buttonin a styled template that names nocursor-pointer, itself or in the helper that builds its classesThe daisyUI gallery's focus rings draw in v4.
focus:outline-nonesets the outline style to none andfocus-visible:outline-2only sets a width, so the breadcrumb links and theforced-colorsfallbacks of the menu, select and tabs examples (48 classes) never drew a ring; each now hasoutline-solidunder the same variants, as the Base UI examples doThe class names the kit ships are Tailwind v4's, not v3's. v4 kept most v3 names as aliases, so nothing failed to compile — a class just meant something other than what it was written for. Every class in the templates, demos, showcase examples, usage rules and hooks was compiled with Tailwind 4.3.3 and none is a name v4 dropped (
bg-opacity-*,flex-shrink-*,overflow-ellipsisand the rest of that list are not in the kit); what was left is below, andTailwindV4ClassesTestreads every class string, the showcase examples and the exported bundles for any of itThe renamed scale takes its v4 names:
shadow-smisshadow-xs(39 base variants), a bareshadowisshadow-sm,blurisblur-sm,backdrop-blur-smisbackdrop-blur-xs,rounded-smisrounded-xsand a bareroundedisrounded-sm, with every side and corner form (rounded-tisrounded-t-sm,rounded-sisrounded-s-sm,rounded-eeisrounded-ee-sm). 148 classes in the templates; the size each one draws does not changefocus:outline-noneisfocus:outline-hiddenin the 38 places the templates use it. v4'soutline-noneremoves the outline for forced-colors users too;outline-hiddenis the v3 class, an invisible outline that still shows there. The checkbox and radio card focus ring drops the bareoutlineit set besideoutline-2, which sets the style in v4bg-gradient-to-*isbg-linear-to-*in the 371 gradient classes of the buttons, badges, alerts, banners, cards, pagination, progress, stepper, chat and mega menu, with theirhover:,rtl:and arbitrary-variant forms. Thefrom-,via-andto-stops are as they wereThe important modifier is written at the end (
top-0!,[&_.indicator-top-left]:translate-x-0!,size-2!), v4's spelling; the leading!is only accepted as a deprecated form. 187 classes, most of them the avatar indicator positionsThe drawer and the sidebar bring a panel back into view with
translate-nonewhere they addedtransform-none. v4 moves a panel with thetranslateproperty, whichtransform-nonedoes not reset, so a custom position class that survived the removal of-translate-x-fullwould have stayed in placeA border or divider has a colour of its own. Tailwind v4 draws
border,border-*anddivide-*incurrentColorwhere v3 drew gray-200, so a width class with no colour followed the text colour. Every component was rendered with each variant and colour and its widths matched to colours: the borderedwhiteanddarkaccordion draw their item separators in the wrapper's border colour, as every other colour does; a button group's separators arebase-border-light/base-border-dark(through:where(), so a button with its own border colour keeps it); the defaultcomboboxtrigger takes the same pair; thedropdowngradient variant draws no border, like the gradient variant of every other component; the sidebar toggle, the file field's upload item and the blockquote's caption divider take a colour. A render test of the generated components fails on a border or divider that has noneextra_smallandsmallare two sizes again. Tailwind v4 moved the scale ofrounded,shadow,blur,drop-shadowandbackdrop-blurdown one step, sorounded-smand a bareroundedare both 0.25rem, and 50 components mappedextra_smallto the first andsmallto the second: a banner at either size measured 4px.extra_smallisrounded-xsnow, with its side forms (rounded-t-xs,rounded-b-xs,rounded-s-xs,rounded-e-xs,rounded-es-xs,rounded-ee-xs), the 0.125rem thatrounded-smwas in v3. The same fix isshadow-xsin theavatar,galleryandimageshadow sizes andblur-xsin theimageblur filter.smallis as it was; the sizes frommediumup did not move.drop-shadowandbackdrop-blurhave no size helper in the kit. A test reads every helper for two sizes whose classes are one value in v4, with a table of the known pairsA form field renders without
name,valueorlabel.<.email_field name="x" />raisedKeyError :value, becausenameandvaluehad no default and nothing read from a field supplied them.nameandvaluedefault to nil onemail_field,text_field,number_field,password_field,tel_field,url_field,search_field,textarea_field,range_field,input,checkbox_field,group_checkbox,radio_field,group_radioanddate_time_field(andlabelon the last);nameoncheckbox_card,radio_card,color_field,file_field,native_selectandtoggle_field;foronform_wrapper;optionsoninput. The field clause takesfield.nameandfield.valuewhen the caller gave none, since a default that is there already is never replaced byassign_new/3. Atoggle_fieldbound to a true field is checked, and acolor_fieldbound to a field shows its color, where both ignored the field's value. A test renders every generated component with only its required attributesThe banner's
border_positionandrounded_positionname the edge:topdrawsborder-t(and rounds the top corners,rounded-t),bottomdrawsborder-b(and rounds the bottom corners,rounded-b).topdrewborder-b, androunded_positionwas inverted, sotoprounded the bottom corners.border_positiondefaults tobottom, which is whattopdrew, so a banner with neither attribute looks as before; an explicittoporbottomon either attribute now names the edge it says. A test reads everyborder_positionandrounded_positionclause for the edge it namesrounded="none"draws no radius onfooter,form_wrapper,gallery,image,mega_menu,navbar,popover,progress,table,table_content,toggle_field,tooltip,videoand the basetabs; it was printed as the classnone. The catalogs that lackednonelist it, so the CLI offers it. A test fails on a rounded helper with no clause fornoneThe
imageismapattribute is a boolean (<.image ismap />), not a string, and is off by defaultdropdown_triggerno longer declarestrigger_id, which nothing readThe
dropdown,popoverandnavbarexamples putspace,rounded,width,padding,idandtrigger_idon the:triggerand:contentslots, which take onlyclass, and left out theidthe component needs. They are attributes of the component now, and a test fails on a slot attribute in a documented example that no component declares. The same fix is in the dropdown and popover usage rules, where the popover's content is the:contentslot, not the inner blockvariant="unbordered"isborderedin thedrawer,footer,jumbotron,menu,speed_dial,tel_fieldandtoastdocs, the demos and the usage rules, andvariant="ghost"istransparent; the accordion in themenuexample istransparent, notmenu. A test fails on a variant in a template or usage rule that no catalog orcolor_variant/2clause hasThe
progressdocs give the semi-circle defaults its attributes declare (200 and 12) and name the ring'scolor, not aprogress_colorit never took. Thejumbotronusage rules name itsborder_sizeand itstop,bottomandverticalborder positionsThe usage_rules setup in
usage-rules.mdis the 1.2 one:usage_rules: [file: "CLAUDE.md", usage_rules: [:mishka_chelekom]]inproject/0, thenmix usage_rules.sync, and{:mishka_chelekom, sub_rules: ["components/button"]}for one component's rulesA
carouselslide without animagerenders its title and description, and no picture; it raisedKeyError :imageA
range_field<:range_value>without apositionsits at the start; it raisedFunctionClauseErrorA
comboboxwith noidtakes one from itsname(name="user[role]"iscombo-user_role), the same on every render, and a random one only with neither. It was-combo, because the attribute's nil default leftassign_new/3nothing to fill inThe
native_selectoption slot'sdisabledis a boolean (<:option disabled>)The catalogs of
accordion,checkbox_card,checkbox_field,color_field,combobox,date_time_field,galleryandradio_cardlist thenoneandfullrounded values their templates have a clause for, and a test fails on a clause the catalog does not listThe
file_fielddocs and usage rules say whatliveanddropzoneneed (upload, oruploadsandtarget); the dropzone examples in the usage rules passeduploadaloneThe
popoverdemo docs and thenavbarandpopoverdemo samples no longer give a slot atrigger_id, and themenudemo's accordion variant istransparentThe
usage_rulessync test runs the 1.2 configuration (usage_rules:inmix.exs) instead of the 0.1 command-line formThe headless editor adds no inline
<style>of its own, so it draws under a strict Content Security Policy (style-src-elem 'self' 'nonce-…') without a console error. TipTap 3 appends a<style data-tiptap-style>to<head>by default, and the policy blocks it; the TipTap engine now passesinjectCSS: config.injectCSS ?? false. The ProseMirror base rules that style carried (position,overflow-wrap, ligatures off,contenteditable="false"spans,pre, the separator image, the gap cursor, the hidden selection) are Tailwind classes on the editor'ssurface, merged withsurface_class, so TipTap and Milkdown keep them. The editor's own rules inmishka_chelekom_headless.css(the surface fill, no outline,white-space, the empty-document placeholder) are surface classes too and left the stylesheet, so the editor is styled once; every other headless component keeps its stylesheet rules. The gap cursor draws in the current text colour rather than black and pulses with Tailwind'sanimate-pulseinstead of a hard blink.injectCSS: trueandinjectNonceineditor_extensions.jsbring TipTap's own stylesheet back, with a nonce. CodeMirror cannot run without the<style>it mounts, so the sameinjectNoncekey reaches itsEditorView.cspNonce; Lexical and Milkdown inject none. Generate the editor again after upgrading, since the stylesheet no longer carries its rulesThe headless editor's toolbar marks a mark toggled at a collapsed cursor at once. Bold with nothing selected only sets the stored marks, a transaction that changes neither the document nor the selection, so the TipTap engine, which repainted
data-activefromonUpdateandonSelectionUpdate, showed it one keystroke late. It repaints on every transaction now, once per keystroke. Milkdown, Lexical and CodeMirror have no toolbar commands, so nothing lags thereA display utility in a component's
classreplaces the component's own. Tailwind writes display utilities in name order, not in class-list order, so the button's defaultinline-flexbeat a caller'shiddenandclass="hidden md:flex"never hid it. Where a component's own display sits on the element that takes the caller'sclass, it now steps aside when that class names one (hidden,block,grid, …); a display behind a variant (max-md:hidden) leaves it in place, and the button'sdisplayattribute steps aside the same way. Changed:avatar_group,badge(and its dismiss button),button,button_group,button_link,input_button,card_title,chat,checkbox_card,group_checkbox, thecomboboxoption,gallery,indicator,flex,grid,header,pagination(and its buttons), theprogresssections,group_radio,shape,spinner,stat,stat_group,stepper,stepper_section,tr,tabs,timeline_section, and the labels offile_field,radio_field,range_field,ratingandtoggle_field. The modal'shiddenis its closed state, not a display, and staysAn avatar keeps its size in a flex row. Its root clips its content, which lets a flex parent shrink it, so the initials of an avatar without an image (
+20,SB) were cut off in a narrow rowA breadcrumb wraps to the next line in a narrow parent instead of overlapping its items; its icons and separators keep their size, and a separator stays at the end of the item before it
button_link, the headlessbuttonand the headlessanchortakenavigateorpatchonly when it is a string. A key that was present but nil chose its clause anyway, so a destination that came out empty turned the headless button into a link, and sentbutton_linkand the anchor tohref="#"instead of theirhrefThe headless
ratingreads a whole star as3 of 5, not3.0 of 5; a half star still reads2.5 of 5The headless stylesheet hides a closed
fabdial, as it hides every other popup. The dial stayed on the page unless the skin addeddata-closed:hiddenThe CMS bundle names every row the way a CMS stores it, and every reference by that name. A CMS slugifies each component, hook and stylesheet name as it saves the row and rewrites nothing that refers to one; the exporter slugified only the part after the kit's name, so the headless kit shipped
chelekom_headless-buttoncallingchelekom_headless-button-content, stored aschelekom-headless-button-content, and every headless button failed to render its label. The same rule misseddependencies:chelekom-scroll_area(tabs, combobox) andchelekom_headless-tree(tree_select) named rows that do not exist. One function now gives the name a row is written under, a template calls, a dependency lists and a hook key is built from, and a test fails on a row not in its stored form or a reference to a component its kit does not haveThe CMS bundle names a hook by the key a CMS registers it under wherever a template names one, not only in a literal
phx-hook="…"or an attribute's default. The headlesstextareashippedphx-hook={@autosize && "Autosize"}, so on a CMS page the browser loggedunknown hook found for "Autosize"and the textarea never grew; it shipsGlobalChelekomHeadlessAutosize. Every string inside aphx-hook={…}, and the default of every attribute one reads, is rewritten, and the shipped-kits test fails on any hook a component names that its kit does not registerThe
icondocs describe what it renders: ahero-name,classand global attributes. They listedvariant,size,color,animate,aria_labeland non-Heroicon names it never took. Itsdoc_urlis its docs page instead ofinternalThe floating hook (dropdown, popover, tooltip) measures its content out of the flow. The content is moved to
<body>and was measured as a static block there, as wide as the page, before it was made absolute, so the viewport clamp pushed a menu opening under its trigger to the left edge of the page. It is made absolute, and given its width, before it is measured; the first open of a menu whose classes stretch it to the page's width was still measured page-wideThe CMS bundle's value lists come from the axis an attribute is gated on, not only from its name.
alertandflashtake their colour throughkind, which carried no list, so a consumer that casts values droppedkind="danger"and every alert drewnatural;kindnow carries thecolorlist.typeandonlyin a component'sargschoose which functions the generator writes, and that list no longer reaches an attribute:input_button's HTMLtypeshipped["button_group", "button", …]Classes Tailwind drew nothing for:
ease-in-ou(button),::flex-1(pagination),flex-start(stepper),fill-opacity-*(rating),sm:font-inherit(ten fields, nowsm:text-[length:inherit]),bordered-text-…(text_field), and theme colours the theme never defined —*-bordered-hover-*(accordion, now in the theme for every colour),progress-bg(gradient progress, now the track's own colour),table-*(table),default-white-bg(card),natural-bordered-dark(footer),primary-inverted-gradient-indicator-dark(button),custom-black-100(file_field) and the*-bg-*/*-ring-*/dark-*set of date_time_field's bordered variant. A test now holds every theme colour a template names to the themeThe floating hook (dropdown, tooltip, popover) reads no layout while it mounts. It read the page's direction and placed its hidden content on mount, and each of those reads, right after the previous hook moved its content to
<body>, made the browser restyle the whole page: a page with 142 tooltips took about three seconds to show after a LiveView navigation, and about 0.4 seconds now. The direction is read and the content placed when it is shown, and a scroll or a resize places only the content that is openA styled generation no longer wipes a project's own
@themetokens (#511). Chelekom's tokens are set in the plain@themewith igniter_css 1.1'sensure_at_rule_declarations— a token it already has only changes value, a missing one is appended — and the project's--font-*/--color-*and their comments stay; a project's@theme inlineis left alonemix mishka.ui.uninstall --include-csstakes back only what the install set: the vendor@importand Chelekom's tokens. It deleted every@themeblock, the project's own and@theme inlineincluded, and rewrote the whole file even when nothing in it was Chelekom's. A generation followed by an uninstall now givesapp.cssback byte for byte; a token the project changed staysThe first JS hook generated into a project with no
assets/vendor/mishka_components.jswas never registered — the registry was created from its empty template and the update skipped — so a lone headlesschartnever mountedA
css_overridesvalue that is not CSS stops the generation and names the override, instead of being dropped while the default shippedThe MCP
list_css_variablesresource reads the variables and their defaults from the stylesheet; its hand-kept copy (and the sampleconfig.exs) had lost--opacity-baseand--overlay-opacityThe chart's docs named an
--engineoption the generator rejects; it is--lib chartjs/--lib billboard--cmsexport no longer crashes on a helper writtendefp xwithout parenthesesThe headless
radio_groupnever went horizontal. Its root hardcodeddata-orientation="vertical"while the JS engine was already reading that attribute to decide which arrow keys move the selection, so the option was unreachable: there is anorientationattribute now, and the keyboard follows itBreaking:
idis required on the headlessavatar. It was optional, but the hook that tracks the image's loading state keys off it, so an avatar without one silently never resolved its fallback. Phoenix reports the missing attribute at compile time, so an affected call site is a warning rather than something to hunt for at runtimeA guarded helper clause keeps its discriminators.
Discriminators.extract_head/1stripped thewhenguard when building its lookup key while the exporter wrote that guard INTO the clause'sargs, so the two signatures could never match and all 867 guarded clauses in the kit shipped with an emptydiscriminatorslist — most of the option lists a consumer needs to build a pickerAdd headless
Editorcomponent (TipTap 3 parity) — rich-text editing via anEditorJS engine (hook on an innerphx-update="ignore"surface, hidden textarea mirror so it submits as an ordinary form field, toolbar buttons wired bydata-editor-command), with a Phoenix form demoAdd npm dependency support to the generators — a component can declare
npm:in its catalog andmix mishka.ui.gen.headless <name>installs it (npm/bun/yarn auto-detected, falling back to the{:bun, ...}hex binary so no system Node is required), gitignoresassets/node_modulesand prepends the install to theassets.setup/build/deployaliases so CI and Docker builds work.--no-npmskips the install; npm-backed components are excluded frommix mishka.ui.gen.*.componentsunless named explicitly or--with-npmis passedAdd headless
Treecomponent — Mantine's Tree converted to a Phoenix headless component, with expand/collapse, single/multiple and shift-range selection, cascading checkboxes (with indeterminate) orcheck_strictly, WAI-ARIA treeview keyboard navigation, drag & drop, and server-driven async child loadingAdd Base UI gallery example and live server-driven examples (controller, form, single event, async, drag & drop, search) for the
TreecomponentAdd headless
EmptyStatecomponent — Mantine's EmptyState converted to a Phoenix headless component: an optional indicator,title/descriptionshorthands, extra body content and an actions row, aligned viadata-align(left/center/right); ships no colors, spacing or role (presentational — addrole="status"for dynamically shown states)Add headless
CloseButtoncomponent (Mantine parity) — an icon-only button with a requiredaria-label, custom-icon slot anddata-disabledAdd headless
Burgercomponent (Mantine parity) — a hamburger navigation toggle witharia-expanded/aria-controlsanddata-openedAdd headless
Chipcomponent (Mantine parity) — a selectable pill backed by a native checkbox/radio input, checked styling via:has(:checked)Add headless
Pillcomponent (Mantine parity) — a compact tag/token with an optional accessible remove button anddata-disabledAdd headless
TagsInputcomponent (Mantine parity) — removable tokens plus a draft input; add via a formphx-submitoron_add, remove viaon_remove, click-to-focus viaJS.focus, no JS hookAdd headless
Spoilercomponent (Mantine parity) — clamp long content behind a Show more / Show less toggle viaJS.toggle_attribute, no JS hookAdd headless
ColorSwatchcomponent (Mantine parity) — display a single color as a labelledrole="img"swatch with optional overlayAdd headless
Codecomponent (Mantine parity) — inline<code>or a<pre><code>blockAdd headless
Markcomponent (Mantine parity) — highlight an inline run of text with<mark>Add headless
VisuallyHiddencomponent (Mantine parity) — hide content visually while keeping it available to screen readersAdd headless
ThemeIconcomponent (Mantine parity) — a container that wraps an icon, decorative or labelledAdd headless
ActionIconcomponent (Mantine parity) — an icon-only action button with a required accessible labelAdd headless
Anchorcomponent (Mantine parity) — a plain, themeable linkAdd headless
Marqueecomponent (Mantine parity) — seamless CSS-only scrolling row (content duplicated, second copyaria-hidden), no JS hookAdd headless
NumberFormattercomponent (Mantine parity) — render-time number formatting with thousands/decimal separators and prefix/suffix, no JSAdd headless
HueSlidercomponent (Mantine parity) — a 0–360° hue picker reusing the sharedSliderengine, no new JSAdd headless
AlphaSlidercomponent (Mantine parity) — a 0–100 opacity picker reusing the sharedSliderengine, no new JSAdd headless
Splittercomponent (Mantine parity) — two resizable panes via aSplitterJS engine (pointer drag + keyboard,role="separator")Add headless
Scrollercomponent (Mantine parity) — horizontal scroll row with prev/next controls via aScrollerJS engine (ResizeObserver end-detection)Add headless
RollingNumbercomponent (Mantine parity) — animate a number to its value via aRollingNumberJS engine (rAF, reduced-motion aware)Add headless
ColorPickercomponent (Mantine parity) — saturation/value drag area + hue slider via aColorPickerJS engine (HSV↔hex, hidden input for forms)Add headless
Highlightcomponent (Mantine parity) — wrap case-insensitive matches of one or more query terms in<mark>at render time, no JSAdd headless
SemiCircleProgresscomponent (Mantine parity) — a half-circle SVG gauge (role="progressbar") computed at render time, no JSAdd headless
NavLinkcomponent (Mantine parity) — a nav item that's a<.link>leaf or a native<details>disclosure with nested children (data-active/aria-current), no JSAdd headless
JsonInputcomponent (Mantine parity) — a JSON textarea with a server-validateddata-invalidstate (parse/format viaJasonin LiveView), no JSAdd headless
SegmentedControlcomponent (Mantine parity) — a row of native radios with:has(:checked)selection and Arrow-key navigation, no JSAdd headless
LoadingOverlaycomponent (Mantine parity) — an absoluterole="status"loader overlay toggled byvisible(CSS fade), no JSAdd headless
PillsInputcomponent (Mantine parity) — an input-shaped container for pills + a text field, click-to-focus viaJS.focus, no JS hookAdd headless
MaskInputcomponent (Mantine parity) — format-as-you-type text field driven by aMaskInputJS engine (9/a/*pattern), with a Phoenix form demoAdd headless
AngleSlidercomponent (Mantine parity) — circular 0–360° dial driven by anAngleSliderJS engine (pointer + arrow keys,--anglefill var), with a Phoenix form demoAdd headless
OverflowListcomponent — single-row list that collapses overflow into a+Ncounter via anOverflowListResizeObserverengine, with anon_changeserver round-trip demoAdd headless
FloatingIndicatorcomponent (Mantine parity) — a highlight box that measures and slides over the active target via aFloatingIndicatorJS engine, with anon_changeserver round-trip demoAdd headless
FloatingWindowcomponent (Mantine parity) — a draggable, clamped panel via aFloatingWindowJS engine (on_moveserver round-trip, non-drag handle controls), with a demoAdd headless
ColorInputcomponent (Mantine parity) — hex field + swatch opening a color picker popover (reuses theColorPickerengine with two-way hex editing, JS-command popover), with a Phoenix form demoAdd headless
TreeSelectcomponent (Mantine parity) — a JS-command disclosure that opens atreein a popover to pick a value, with a Phoenix form demo wiring the tree'son_selectAdd
Mishka Toolsdocumentation button to headless component pages, and pointARIA patternat the component'sspec_urlinstead of its docs URLAdd per-option tagged, base-first
examplestomix mishka.ui.export --cms: every component now ships at least one example, ordered base-first, withextra.examples[]carryinglabel/section/base/requiresso a consumer can hide an example whose variant was not installed CommitAdd
## Examplesdocs tolabel/1,error/1,header/1andsimple_form/1, so every public component function documents its usageAdd headless
Chartcomponent — one charting API over three swappable engines: Apache ECharts by default, Chart.js or billboard.js on request. Each engine installs under a single file name, so switching engines replaces the vendored file instead of stacking them, and every engine is exact-pinned and permissively licensedAdd headless
Sparklinecomponent — a server-rendered SVG trend line with no npm package, no scripts and no JS hook, so it renders in a table cell, a stat card or an email, whichever chart engine (if any) you generatedAdd
decode_atom_map/1beside the__atom_map__encoder, so a consumer can read a bundle's encoded atom keys back without reimplementing the format
Mob (native Android and iOS):
Mob renders native Jetpack Compose and SwiftUI from Elixir. Every component below is a native port
of its headless counterpart — the same props and the same event contract, with no styling of its
own — generated by mix mishka.ui.gen.mob and written as a tag, <Accordion />, exactly like the
Phoenix component it mirrors.
- Add
mix mishka.ui.gen.mob,mix mishka.ui.gen.mob.componentsandmix mishka.ui.gen.mob.kitto generate native Mob components into a Mob application, honouring--module-prefixand carrying each component's kit dependencies with it - Add Mob support to
mix mishka.ui.uninstall - Add
mix e2eto run the on-device Compose test suites against a connected emulator or handset - Add usage rules for every generated Mob component, alongside the existing headless ones
- Add
Accordioncomponent for Mob - Add
ActionIconcomponent for Mob - Add
AlertDialogcomponent for Mob - Add
AlphaSlidercomponent for Mob - Add
Anchorcomponent for Mob - Add
AngleSlidercomponent for Mob - Add
Autocompletecomponent for Mob - Add
Avatarcomponent for Mob - Add
Burgercomponent for Mob - Add
Checkboxcomponent for Mob - Add
CheckboxGroupcomponent for Mob - Add
Chipcomponent for Mob - Add
CloseButtoncomponent for Mob - Add
Codecomponent for Mob - Add
Collapsiblecomponent for Mob - Add
ColorInputcomponent for Mob - Add
ColorPickercomponent for Mob - Add
ColorSwatchcomponent for Mob - Add
Comboboxcomponent for Mob - Add
ContextMenucomponent for Mob - Add
Dialogcomponent for Mob - Add
Drawercomponent for Mob - Add
EmptyStatecomponent for Mob - Add
Fieldcomponent for Mob - Add
Fieldsetcomponent for Mob - Add
FloatingIndicatorcomponent for Mob - Add
FloatingWindowcomponent for Mob - Add
Highlightcomponent for Mob - Add
HueSlidercomponent for Mob - Add
JsonInputcomponent for Mob - Add
LoadingOverlaycomponent for Mob - Add
Markcomponent for Mob - Add
Marqueecomponent for Mob - Add
MaskInputcomponent for Mob - Add
Menucomponent for Mob - Add
Menubarcomponent for Mob - Add
Metercomponent for Mob - Add
NavLinkcomponent for Mob - Add
NavigationMenucomponent for Mob - Add
NumberFieldcomponent for Mob - Add
NumberFormattercomponent for Mob - Add
OtpFieldcomponent for Mob - Add
OverflowListcomponent for Mob - Add
Pillcomponent for Mob - Add
PillsInputcomponent for Mob - Add
Popovercomponent for Mob - Add
PreviewCardcomponent for Mob - Add
Progresscomponent for Mob - Add
Radiocomponent for Mob - Add
RadioGroupcomponent for Mob - Add
RollingNumbercomponent for Mob - Add
ScrollAreacomponent for Mob - Add
Scrollercomponent for Mob - Add
SegmentedControlcomponent for Mob - Add
Selectcomponent for Mob - Add
SemiCircleProgresscomponent for Mob - Add
Separatorcomponent for Mob - Add
Skeletoncomponent for Mob - Add
Slidercomponent for Mob - Add
Splittercomponent for Mob - Add
Spoilercomponent for Mob - Add
Switchcomponent for Mob - Add
Tabscomponent for Mob - Add
TagsInputcomponent for Mob - Add
ThemeIconcomponent for Mob - Add
Toastcomponent for Mob - Add
Togglecomponent for Mob - Add
ToggleGroupcomponent for Mob - Add
Toolbarcomponent for Mob - Add
Tooltipcomponent for Mob - Add
Treecomponent for Mob - Add
TreeSelectcomponent for Mob - Add
VisuallyHiddencomponent for Mob
Refactors:
- Refactor the
--cmsexport example pipeline intoCmsBundle.{DocExamples, DocsPage, Examples, Sanitize}, harvesting from each function's@docfences and the docs pages'code_string/1snippets rather than the demo markup - Update
phoenix_live_viewto 1.2.7 Commit - Point
doc_urlat mishka.tools and preserve the specification URLs underspec_urlCommit - Add the Headless section to the README Commit
- Tighten all 116 usage rules, fix the Kit doc, bump versions and add the v0.0.9 roadmap Commit
- Shorten every usage rule Commit
- Generated components pass
mix credo --strict: the--importmacro carries a@moduledocand lists its imports as{module, opts}entries inimports/0instead of one longquoteblock (mix mishka.ui.uninstalledits both this shape and the older one), and the styled and headless templates credo flagged are refactored without changing their rendered markup
Bugs:
- Fix missing
component_prefixin components Commit - Fix Tabs not showing a pointer cursor on hover over tab triggers #491
- Fix avatar not forwarding standard
imgattributes (alt,srcset,loading,width…) via:globalinclude Commit - Fix Elixir 1.20 type-checker warnings in stepper and table_content Commit
- Fix dev harness headless CSS copy drifting from the
privsource Commit - Fix
--cmsexport shipping no examples for 53 of 136 components: the form components' docs pages were never vendored, nested-only components (card_title,td,progress_section…) were skipped by the extractor, and the literal-only filter discarded every snippet that referenced a demo assign (paginationharvested 111 examples and shipped 0) - Fix
DemoHarnessnot passingextra.clauses,extra.preludeandextra.module_attributesto the component compiler, so every multi-clause component was compiled from its first clause only and guarded clauses were never exercised - Fix component compiler dropping multi-clause guards, which made all nine form-field components raise
FunctionClauseErroron render with their defaultfloatingvalue - Fix
file_fielddropzone never opening the file picker:live_file_input/1identifies its input by the upload ref and ignores a callerid, so the label'sforresolved to nothing and the label lost its control entirely. The label now points at@upload.ref, the caller'sidmoves to the wrapper, and the previously undeclareduploadattribute is declared #496
Changelog for MishkaChelekom 0.0.9
Features:
- Add Components prefix name in CLI and config file #454
- Add Module prefix name in CLI and config file #459
- Add
--no-saveflag to control prefix config saving #459 - Add Usage rules for all components and JS Hooks #461
- Add uninstall Mix task and its tests #464
- Add Entry-level MCP for Mishka Chelekom components, docs and CLIs #466
- Add server push event for
Comboboxcomponent Issue with help - Add
Disabled State,Half-Star Precision,Form integrationinto rating component Issue with help - Add dock (bottom-navigation) component Issue with help
- Add Shape component
- Add Stat component
- Add harness demo driven kit test for dynamic CMS generator (Private APIs) #479
- Add stdio transport + mix mishka.mcp.setup --stdio Issue with help
- Add entry-level headless components ported from Base UI for Phoenix #489
- Add creatable option support to Combobox component Commit
- Add scrollable trigger list (
scroll_area) for Tabs in vertical orientation Issue with help - Add
--headlessflag tomix mishka.ui.uninstalland make--allremove both styled and headless components - Add
MishkaChelekom.Kit— a Spark DSL (customize/from) to reuse and restyle existing styled and headless components without editing their files - Add
mix mishka.ui.gen.kitto vendor the Kit engine into your app (self-contained catalog +sparkdep), so the Kit works in production with nomishka_chelekomruntime dependency
Refactors:
- Refactor accordion to auto-generate item IDs (Explicit and open dynamic identifiers) Commit and Issue with help
- Change
:classattr type from:stringto:anyin components Commit - Refactor server-render active state so it works on static mount and reacts to assign changes Issue with help - Issue with help
- Refactor generators and asset handling for the headless CLI, with unified per-command banners and improved headless CSS import Commit
- Bump minimum Elixir to 1.18 and add compile-time
JSON/Jasonfallback Commit - Refactor uninstall to restore
CoreComponentsimport #465 - Center the banner subtitle and give every mix task its own title
- Add a consistent Owl loading spinner to every Igniter mix task (
export,gen.component,gen.headless,gen.kit,css.config,assets.deps,mcp.setup)
Bugs:
- Remove stopPropagation from Floating hook to allow phx-click event bubbling Commit and Issue with help
- Fix menu
sub_itemsand sidebarhide_positioncrashes Issue with help - Use native browser date picker icons and remove custom calendar icon Issue with help
- Fix Misplaced dropdown when content has min-width Issue with help
- Fix some missing lables conditions #469
- Fix CSS typos, wrong border classes, swapped docs, and Gettext template bug #468
- Delete dead label code from fieldset component
- Fix readd floating content back to original parent before update#475
- Fix MCP runtime error Commit
- Update and fix version conflict with other Mishka Project Commit
- Fix Only use
Owl.Spinnerwhen TTY available #477 - Fix dropdown content slot class attribute concatenation Commit
- Fix Combobox field attribute not sending values to form params Commit
- Fix Elixir 1.19 and
not ... in ...deprecation warnings Commit - Fix false cross-kind dependency warning when uninstalling a headless component that shares a name with a styled one
- Fix uninstall
--allcomponent discovery for path and umbrella dependencies - Fix
:owlapplication not started before the spinner inmix mishka.ui.gen.headless.components - Fix active mode of Outline Radio Card and Checkbox Card #488 #481
- Fix
show_checkboxprop not applying in Checkbox Card and Radio Card #487 - Fix component colors and gradients across form and menu components, including
form_wrapperdefault variant/color/border andmega_menugradient rendering #485 - Align component catalog (
.exs) variant and color lists with their implementations (unbordered→bordered,gradeint→gradient, corrupted color token, missingtable/tabsvariants) Commit - Fix Combobox dropdown color not matching the selected variant/color and theme the option highlight to follow the chosen color Commit
- Migrate remaining Tailwind v3 utilities to v4 (video track captions, opacity, flex-shrink) #486
- Fix
color_fieldcircleoption having no effect and migrate it to Tailwind v4 #483
Tests:
- Add retire-js and semgrep security scanning #460
- Add Elixir 1.20.2 (OTP 29) to the CI test matrix Commit
- Add direct end-to-end tests for every mix command in the development harness
Changelog for MishkaChelekom 0.0.8
Refactors:
- Update to Tailwind 4 phoenix 1.8 and new cli options for 0.0.8 #439
- Update dependencies
- Update IgniterJS source #40
- Update IgniterCss (but not using in this version, still we have some problems) #14
- Improve
floating.jsto accept update request and better UX - Refactor Tooltip and Popover components
- Refactor Combobox component
Features:
- Add
mix mishka.ui.css.config - Add CSS file to have all components colors and another configs
- Add Config file to override default configs (for example custom css)
- Add simple CSS utilities helper and delete IgniterCss for this version
- Add exclude components option for
mix mishka.ui.gen.components - Add Collapse component
- Add Collapsible JS Hook
- Add Github action for testing
Tests:
- Add unit tests for
mix mishka.assets.deps - Add unit tests for
mix mishka.assets.install - Add unit tests for
mix mishka.ui.add - Add unit tests for
mix mishka.ui.css.config - Add unit tests for
mix mishka.ui.export - Add unit tests for
mix mishka.ui.gen.component/components
Bugs:
- Fix some bugs of
mix mishka.ui.addandmix mishka.ui.export - Fix some problems of new changes of Phoenix and LiveView
- Fix typos
- Fix Owl error conflict version with Ash generator Discord
- Fix duplicated IDs in
dropdowncomponent - Fix installation issues of Ash Igniter
Changelog for MishkaChelekom 0.0.7
Refactors:
- Flash group restriction for Phoenix version 1.8 #424
Changelog for MishkaChelekom 0.0.6
Features:
- Add install version of
mishka.assets.depsmix command #413 - Add remove JS package for
mix mishka.assets.depscli #414
Bugs:
- Add temporary patch for fixing Phoenix 1.8 Flash group
Changelog for MishkaChelekom 0.0.5
Features:
- Add layouts flex and grid components #330
- Add filterable gallery to the Gallery component #332
- Add Circular and Semicircle Progress bar to progress component #333
- Add support for fractional values to the rating component #334
- Add tooltip to progress section #335
- Add Clipboard component and hook integration #337
- Add ability to to Minimize and Maximize Sidebar #339
- Adding basic accessibility support to all components
Refactors:
- Fix Dropdown Bugs and Enhance Dynamic Behavior #328
- Add conditional styling to divider and buttons #329
- Add Custom Hook, Loading State, and Bug Fixes of Carousel Component #336
- Replace custom icon functions with shared icon component #338
- Implement Toast and Alert components to support z-index prop #399
- Update Igniter to last version
Changelog for MishkaChelekom 0.0.4
Bugs:
- Fix Stepper icon display issue #338
Features:
- Add on_select attribute on tab slot
- Add scroll area component #296 #300
- Add missing features of Phoenix core components #296
- Add global components installing support and JS formatter #304
- Add radio card component #305
- Add checkbox card component #306
- Add combobox component #321
Bugs:
- Add missing slot to gallery component #294
- fix typo in tab, checkbox field, radio field components #295
- Fix missing ids in table and Flash assign_new to create new id from pattern #313
- Fix color and variants functions of stepper component #338
Refactors:
- Refactor some Phoenix CoreComponent backward compatibility issues for Ash #312
- Refactor and Use more generous dependency on igniter #317
- Reset line height of alert #320
- Skipping Color in the Base Variant #322
- Fix color of radio and checkbox fields #324
Changelog for MishkaChelekom 0.0.3
Features:
- Support JS community cli version (beta) #254
- Support Export community cli version (beta) #256
- Add paddings and width fit to alert #287
- Add badge to tab component #290
- Add Igniter installer mix task
Bugs:
- Fix alert title type #288
- Fix some issues about windows PowerShell
Changelog for MishkaChelekom 0.0.2
Features:
- Support community cli version (beta) #92
- Supports cli helpers import #93
- Update all templates for new syntax
{}(Phoenix LiveView 1.0.0)
Refactors:
- Fix Adjust spacing for checkbox and radio fields #73
- Add dark mode and fix issues of gradient variants of Button component #91
- Add dark mode and fix issues of gradient variants of Badge component #94
- Add dark mode and fix issues of Overlay of Drawer component #96
- Add dark mode of Divider component #97
- Add dark mode of Avatar component #98
- Add dark mode of Alert component #99
- Add dark mode of Spinner component #100
- Add dark mode of Banner component #101
- Add dark mode of Breadcrumb component #102
- Add dark mode of Blockquote component #103
- Add dark mode of Dropdown component #104
- Add dark mode of Overlay component #106
- Add dark mode of Card component #107
- Add dark mode and add
show_arrowprop of Popover component #121 - Add dark mode of Rating component #123
- Add dark mode of Chat component #125
- Add dark mode of Modal component #126
- Add dark mode of Keyboard component #127
- Add dark mode of Jumbotron component #128
- Add dark mode of Indicator component #129
- Add dark mode of Carousel component #130
- Add dark mode of Footer component #132
- Add dark mode of MegaMenu component #133
- Add dark mode of Navbar component #134
- Add dark mode of Progress component #136
- Add dark mode of email, url, search, number, password, textarea, tel, text fields components #138
- Add dark mode of FormWrapper component #140
- Add dark mode of RadioField component #143
- Add dark mode of CheckboxField component #144
- Add dark mode of Sidebar component #145
- Add dark mode of DateTimeField component #146
- Add dark mode of Tooltip component #147
- Add dark mode of Video component #148
- Add dark mode of Typography component #149
- Add dark mode of ToggleField component #150
- Add dark mode of SpeedDial component #151
- Add dark mode of Skeleton component #152
- Add dark mode of TableOfContent component #153
- Add dark mode of Timeline component #154
- Add dark mode of Table component #155
- Add dark mode of Tabs component #156
- Add dark mode of NativeSelect component #158
- Add dark mode of RangeField component #159
- Add dark mode of Toast component #160
- Add dark mode of List component #161
- Add dark mode of Fieldset component #162
- Add dark mode of FileField component #163
- Add dark mode of Stepper component #165
- Add dark mode of Accordion component #166
- Add dark mode of DeviceMockup component #167
- Add dark mode of pagination component #168
- Add full width to button #170
- Add filter props to image component #171
- Add other line styles to timeline #172
- Add loader to slot to button component #173
- Add radius to toggle component #174
- Add space based on sizes to pagination component #175
- Add label slot to each chunk of progress #176
- Add separated variant to table #178
- Refactor: Fix issue of zooming inputs #185
- Modify structure of popover and dropdown components #189
- Add animations to gallery #190
- Stop spinner when an image is in done #194
- Modify styles of form fields, add new prop to badge #192
- Modify card and overlay components styles #193
- Modify table content component #195
- Add variant to stepper, add loading state to stepper #196
- add hoverable prop to listdd #197
- Add classes to badge #257
- Add new styles to tabs #273
- change structure of tooltip #277
- Add and remove unnecessary classes textarea field #276
- Add and remove unnecessary classes text field #275
- Add and remove unnecessary classes tel field #274
- Add new variants to table #272
- Change styles in stepper #271
- Add and remove unnecessary classes of search #270
- Add line height class to rating button #269
- Change styles of progress #268
- Change structure of popover #267
- Add and remove unnecessary classes number field #265
- Add new props and fix color issues, remove extra functions from list #263
- Add and remove unnecessary classes from email field #261
- Add and remove unnecessary classes from date field #260
- change chat section styles #259
- Add new prop to card media #258
Bugs:
- Fix un-CSP progress mounted #72
- Fix modal title
default: nilvalue #76 - Correct typo separated across the project #81
- Revision and fix some missing part of some fields (version 0.0.1) #84
- Fix without
--importoption error of components task CLI b0b7492 - Fix issue of breadcrumb RTL mode #170
- Remove space-y-0 classes from Menu, Footer, Navbar, Tooltip components #183
- Delete none pattern functions from all components #246
- Fix issues of password field #266
- Fix issues of shadow in native select #264
- Fix style issues of fieldset #262
- Fix some global issues
Changelog for MishkaChelekom 0.0.1
We are delighted to introduce our new version of MishkaChelekom fully featured components and UI kit library for Phoenix & Phoenix LiveView. Kindly ensure that the MishkaChelekom Library is updated as quickly as feasible.
For more information please see: https://mishka.tools/chelekom
Features:
Add generator mix CLI task for creating component
Add generator mix CLI task for creating components
Add basic components (light mode version)
<details>
<summary>Components list</summary>
- [x] accordion
- [x] alert
- [x] avatar
- [x] badge
- [x] banner
- [x] blockquote
- [x] breadcrumb
- [x] button
- [x] card
- [x] carousel
- [x] chat
- [x] chekbox_field
- [x] color_field
- [x] date_time_field
- [x] device_mockup
- [x] divider
- [x] drawer
- [x] dropdown
- [x] email_field
- [x] fieldset
- [x] file_field
- [x] footer
- [x] form_wrapper
- [x] gallery
- [x] image
- [x] indicator
- [x] input_field
- [x] jumbotron
- [x] keyboard
- [x] list
- [x] mega_menu
- [x] menu
- [x] modal
- [x] native_select
- [x] navbar
- [x] number_field
- [x] overlay
- [x] pagination
- [x] password_field
- [x] popover
- [x] progress
- [x] radio_field
- [x] range_field
- [x] rating
- [x] search_field
- [x] sidebar
- [x] skeleton
- [x] speed_dial
- [x] spinner
- [x] stepper
- [x] table
- [x] table_content
- [x] tabs
- [x] tel_field
- [x] text_field
- [x] textarea_field
- [x] timeline
- [x] toast
- [x] toggle_field
- [x] tooltip
- [x] typography
- [x] url_field
- [x] video
</details>
Add white primary secondary dark success warning danger info light misc dawn colors
Add common sizes
Add common variants
Add common positions
Docs
- Add generator docs
- Add basic components docs