Système de composants sans interface · Nouvelle ressource

Système de design Kobalte.

Kobalte fournit des composants headless pour Solid, notamment des champs numériques avec valeurs brutes et formatées distinctes, une anatomie composée de cases à cocher et des boutons avec état activé. Ce guide relie ces primitives aux signaux Solid au moyen d’un outil de mise à l’échelle de recettes qui calcule les quantités et permet de réinitialiser les ingrédients cochés.

Guide OpenDesign9 chapitres29 entrées de référenceGuide de l’application d’origine
01

Aperçu de l’interface du système de design Kobalte

Ajustez les quantités d’ingrédients, rassemblez les éléments et épinglez une recette originale localement.

Fiche de recette réactiveOuvrir l’exemple complet
Kobalte 0.13.14 avec Solid 1.9.15 ; primitives natives sans interface imposée et CSS original complet. · Référence de mise en œuvre
02

Référence de conception du système de design Kobalte

Kobalte 0.13.14 fournit des primitives Solid sans interface imposée, mais pas d’échelle visuelle canonique. Toutes les couleurs et dimensions recipe-* ci-dessous constituent la configuration complète de l’application originale. Les noms API et les attributs d’état ont été vérifiés dans le package installé et la documentation officielle des composants.

Couleurs sémantiques d’origine

Source
Nom / règleValeur / configurationUtilisation
--recipe-canvas#f6f2ec Arrière-plan général
--recipe-surface#fffefa Panneaux de recette et de portions
--recipe-ink#403a30 Texte principal
--recipe-muted#807465 Texte secondaire
--recipe-line#e6ded2 Séparateurs et bordures
--recipe-action#95612f Case à cocher sélectionnée et texte d’action
--recipe-on-action#fffTexte sur fond d’action plein
--recipe-focus#b88955 Indicateur de focus clavier visible
--recipe-soft#f1e4d3 Arrière-plan du sélecteur et de l’épingle activée

Typographie et dimensions d’origine

Source
Nom / règleValeur / configurationUtilisation
Bodysystem-ui, sans-serifAucun téléchargement de police
Page heading34px / 1.15; 29px narrowHiérarchie d’origine
Recipe titleGeorgia, serif; 30px / 1.2Accent éditorial d’origine
Ingredient copy13px / 1.5; 12px narrowLibellés lisibles sur plusieurs lignes
--recipe-space-1 / 2 / 34px / 8px / 12pxPetits espacements
--recipe-space-4 / 6 / 816px / 24px / 32pxEspacement des panneaux et de la page
Panel radius16pxGéométrie des surfaces d’origine
Checkbox control21 × 21px; 5px radiusIndicateur visible d’origine
Stepper trigger42px wideDéclencheur natif à la géométrie d’origine
Layout breakpoint760pxDeux colonnes deviennent une seule
Focus ring3px; 3px offsetTraitement du clavier visible d’origine

Contrat d’état du composant natif

Source
Nom / règleValeur / configurationUtilisation
NumberField.rawValuenumberÉtat arithmétique plutôt que texte formaté
NumberField.onRawValueChange(value: number) => voidMet à jour les quantités et efface les sélections obsolètes
minValue / maxValue / step1 / 8 / 1Limites de l’application transmises au champ numérique natif
formatOptions.maximumFractionDigits0Affichage en portions entières
validationStatevalid | invalidValidité de l’application reflétée dans le champ natif
Checkbox.checked / onChangeboolean / callbackSélection contrôlée des ingrédients
Checkbox data attributesdata-checked; data-focus-visibleStyliser les états natifs coché et focus clavier
ToggleButton.pressed / onChangeboolean / callbackÉpingle locale contrôlée
ToggleButton data-pressedpresent when pressedStyle de l’épingle locale activée
03

Guide complet du système de design Kobalte

Un guide pratique pour choisir, appliquer et évaluer ce système dans une interface réelle.

DESIGN-kobalte.md

Des conseils complets, un point de départ pour la mise en œuvre et des liens vers les sources.

Télécharger le guide

Système de design Kobalte : connecter les composants Kobalte aux signaux Solid

Connecter les composants Kobalte aux signaux Solid

Le composant utilise des signaux Solid pour les portions, les ingrédients rassemblés et l’épingle. createMemo déduit la validité du signal numérique, et For affiche une collection d’ingrédients stable. Les propriétés contrôlées de Kobalte lisent directement ces signaux ; les mises à jour ne nécessitent ni fournisseur de formulaire distinct ni adaptateur d’état de type React.

Extrait de ce guide OpenDesign

NumberField, Checkbox et ToggleButton sont importés depuis leurs points d’entrée respectifs. Leurs rôles diffèrent : le champ numérique gère la saisie numérique modifiable, chaque case à cocher représente un ingrédient rassemblé et le bouton bascule conserve l’épingle de la recette. Les règles de calcul et d’invalidation restent dans les fonctions de l’application, au lieu d’être intégrées aux sélecteurs visuels.

Consultez la spécification associée

Système de design Kobalte : distinguer l’état numérique du texte formaté

Distinguer l’état numérique du texte formaté

NumberField reçoit rawValue={portions()} et onRawValueChange={update}. Le signal numérique commande directement la multiplication, tandis que le champ gère le formatage et la saisie de l’utilisateur. Réinjecter le texte formaté affiché dans les calculs imposerait des hypothèses d’analyse concernant les séparateurs ou les paramètres régionaux, auxquelles la primitive native répond déjà.

L’exemple autorise de une à huit portions entières, avec un pas de un et maximumFractionDigits défini sur zéro. Un prédicat calculé séparément vérifie tout de même que la valeur est finie, entière et comprise dans les limites, car un champ modifiable peut momentanément contenir une valeur incomplète ou invalide. En cas de valeur invalide, les totaux affichent un tiret cadratin et les cases à cocher des ingrédients sont désactivées. L’interface n’affiche pas une quantité plausible mais incorrecte comme si l’utilisateur avait fourni une valeur valide.

Consultez la spécification associée

Système de design Kobalte : composer le champ à partir de son libellé et de ses messages natifs

Composer le champ à partir de son libellé et de ses messages natifs

Le champ numérique contient Label, DecrementTrigger, Input, IncrementTrigger, Description et ErrorMessage. La description visible explique à la fois la plage de valeurs et les conséquences d’un changement du nombre de portions. Les déclencheurs portent des libellés explicites, Moins de portions et Plus de portions ; leurs signes moins et plus n’ont donc pas à constituer à eux seuls leur nom accessible.

validationState passe de valide à invalide selon le prédicat de l’application. ErrorMessage appartient à ce champ natif, et non à un paragraphe sans lien placé ailleurs sur la page. Pour un formulaire envoyé, Kobalte fournit également un HiddenInput pour la sérialisation des valeurs brutes ; cet exemple local n’en inclut pas, car il ne possède ni point de terminaison d’envoi ni charge utile de formulaire.

Consultez la spécification associée

Système de design Kobalte : gérer la sélection des ingrédients dans un ensemble immuable

Gérer la sélection des ingrédients dans un ensemble immuable

Chaque ingrédient utilise l’anatomie complète de Checkbox : Input, Control, Indicator et Label. Le véritable champ de saisie préserve la sémantique et l’interaction au clavier, tandis que le contrôle visible reçoit la coche et les styles d’état d’origine. Le libellé inclut le nom de l’ingrédient et sa quantité, qui fait ainsi partie de l’élément que le lecteur rassemble.

mark crée un nouvel ensemble Set à partir de la sélection précédente avant d’ajouter ou de supprimer un ID. La simple mutation de l’ensemble Set existant ne déclencherait pas une mise à jour de signal aussi fiable. Le nombre affiché correspond à la taille de l’ensemble Set, et chaque Checkbox vérifie l’appartenance à l’ensemble à l’aide d’un ID d’ingrédient stable. Tout changement de quantité efface l’ensemble de la sélection, car le fait d’avoir rassemblé 320 grammes ne prouve pas que le nouveau besoin de 400 grammes est satisfait.

  • Associez chaque nom d’ingrédient visible à Checkbox.Label.
  • Conservez Checkbox.Input, même si le carré visible est personnalisé par des styles.
  • Utilisez des ID stables pour la sélection et créez un nouvel ensemble Set à chaque mise à jour.

Consultez la spécification associée

Système de design Kobalte : utiliser un Toggle pour un choix local persistant

Utiliser un bouton bascule pour un choix local persistant

L’épingle est un ToggleButton doté de pressed et onChange, et non un bouton ordinaire qui change uniquement son libellé. Son état pressed est reflété dans la sémantique native et le sélecteur data-pressed. Le libellé devient « Épinglée » avec une coche, et le statut à proximité indique que cela ne concerne que l’aperçu local.

L’épinglage ne modifie ni les quantités d’ingrédients ni leur sélection. Le changement du nombre de portions efface les cases cochées des ingrédients, mais conserve l’épingle, car l’identité de la recette n’a pas changé. La restauration de la recette par défaut réinitialise ensemble les trois aspects du modèle : quatre portions, un Set d’ingrédients vide et une épingle non activée. Ces différentes limites de réinitialisation respectent le sens de chaque état au lieu de tout effacer à chaque interaction.

Consultez la spécification associée

Système de design Kobalte : fournir une configuration visuelle reproductible aux contrôles headless

Configurer les contrôles sans interface imposée de façon reproductible

La feuille de style de la recette distingue la surface de saisie du champ numérique, ses boutons d’incrémentation et de décrémentation, et le rôle de sélection de la case à cocher. Le texte atténué des ingrédients ne s’applique qu’après leur validation ; les quantités restent lisibles afin que l’utilisateur puisse comparer les quantités rassemblées au nombre de portions actuel.

L’espacement utilise des valeurs de quatre, huit, douze, seize, vingt-quatre et trente-deux pixels. La hiérarchie typographique d’origine associe une police sans empattement système pour les contrôles à Georgia pour le titre de la recette. Une case à cocher visuelle de vingt et un pixels se trouve à côté d’un libellé entièrement associé ; le libellé reste la zone d’activation la plus pratique. Toutes ces valeurs exactes figurent dans le CSS complet, afin que le lecteur puisse reproduire l’exemple sans avoir à deviner à partir d’une capture d’écran.

Consultez la spécification associée

Système de design Kobalte : permettre à la composition de se réduire sans masquer d’informations

Permettre à la composition de se réduire sans masquer d’informations

La disposition large associe une fiche recette flexible à un panneau de portions de 280 pixels. À 760 pixels, les éléments s’empilent sur une seule colonne. Le titre de la fiche peut passer sur plusieurs lignes, les libellés des ingrédients peuvent se poursuivre sur la ligne suivante et la quantité reste une valeur compacte qui ne revient pas à la ligne. Au point de rupture le plus étroit, le panneau réduit légèrement ses marges intérieures et la taille des caractères des libellés, plutôt que de masquer les quantités.

L’illustration de la salade est une création originale CSS, marquée comme décorative. Le nom de la recette, le nombre de portions et les quantités d’ingrédients transmettent l’information indépendamment de cette illustration. Conservez les libellés complets des ingrédients et leurs quantités lorsque vous modifiez l’illustration ou réduisez la largeur de la fiche : ce sont les données réellement utilisées pour la tâche de rassemblement des ingrédients.

Consultez la spécification associée

Système de design Kobalte : traiter le changement de quantité comme une mise à jour d’état dépendant

Traiter les changements de quantité comme une mise à jour d’état dépendant

Chaque portion représente 250 grammes répartis entre les cinq ingrédients. Le passage de quatre à cinq portions fait passer le total affiché de 1,000 à 1,250 grammes et la quantité d’oranges requise de 320 à 400 grammes. Les ingrédients déjà cochés sont décochés, car ils correspondaient aux anciennes quantités, tandis que la recette reste épinglée, puisque son identité n’a pas changé.

La fonction de mise à jour compare d’abord la valeur reçue au signal actuel à l’aide de Object.is. Un rappel sans changement ne doit ni effacer la liste de vérification ni signaler une modification de quantité. Les valeurs non valides masquent les quantités et désactivent le rassemblement des ingrédients ; le message d’erreur précise alors la plage autorisée. Ces règles rendent les modifications intermédiaires visibles sans laisser un nombre non valide produire un total trompeur.

  1. Sélectionner les quartiers d’orange pour quatre portions.
  2. Passer à cinq portions et vérifier que les oranges représentent 400 g, le total 1,250 g et le nombre d’éléments rassemblés zéro.
  3. Épingler la recette, puis restaurer les valeurs par défaut et vérifier que tout l’état local est réinitialisé.

Consultez la spécification associée

Système de design Kobalte : utiliser une compilation complète et inclure toute la feuille de style

Utiliser une compilation Solid et inclure la feuille de style complète

La configuration utilise le modèle Vite pour Solid, verrouille les versions vérifiées de Solid et de Kobalte, puis monte l’application dans une racine explicite. Le composant et la feuille de style présentés ci-dessus sont des fichiers complets. Cet exemple ne nécessite ni fournisseur de thème, ni paquet d’icônes, ni police externe, ni backend.

Lors de l’intégration à une autre application, veillez à ce que le compilateur du framework et la génération des composants soient compatibles. Une transformation React ne convertira pas le JSX de Solid en une application Kobalte correcte. De même, avant de remplacer la dépendance verrouillée par une future version majeure de Kobalte API, consultez la documentation correspondante. Les quantités de la recette et la palette sont des données d’exemple de l’application ; leur adaptation ne nécessite donc pas de modifier le contrat des primitives natives.

Consultez la spécification associée

Kobalte Exemples de composants du système de design

Composant de recette réactif complet

Champ numérique natif, structure de case à cocher et bouton à bascule avec gestion explicite des états non valides et de la réinitialisation.

jsx
import {createSignal,createMemo,For} from 'solid-js';
import {NumberField} from '@kobalte/core/number-field';
import {Checkbox} from '@kobalte/core/checkbox';
import {ToggleButton} from '@kobalte/core/toggle-button';
export default function App(){
 const[portions,setPortions]=createSignal(4),[checked,setChecked]=createSignal(new Set()),[pinned,setPinned]=createSignal(false),[notice,setNotice]=createSignal('');
 const ingredients=[{id:'orange',name:'Orange segments',grams:80},{id:'beans',name:'Cooked white beans',grams:90},{id:'leaves',name:'Salad leaves',grams:25},{id:'fennel',name:'Thinly sliced fennel',grams:40},{id:'dressing',name:'Citrus dressing',grams:15}];
 const valid=createMemo(()=>Number.isFinite(portions())&&Number.isInteger(portions())&&portions()>=1&&portions()<=8);
 function update(value){if(Object.is(value,portions()))return;setPortions(value);setChecked(new Set());setNotice('Portions changed. Ingredient checks were cleared for the new quantities.')}
 function mark(id,value){setChecked(previous=>{const next=new Set(previous);value?next.add(id):next.delete(id);return next})}
 function reset(){setPortions(4);setChecked(new Set());setPinned(false);setNotice('Restored four portions and an unchecked ingredient list.')}
 return <main class="recipe-shell"><header><p class="eyebrow">KITCHEN NOTEBOOK · REACTIVE RECIPE CARD</p><h1>A brighter bowl, sized for your table.</h1><p>Change the portions, check the scaled ingredients and pin the recipe locally. The quantities are original sample data for this interface.</p></header><div class="recipe-layout"><section class="recipe-card"><div class="salad-art" aria-hidden="true"><div class="plate"><i/><b/><em/><span/><strong/></div></div><div class="recipe-heading"><div><p class="eyebrow">CITRUS & WHITE BEAN SALAD</p><h2>Fresh, crisp, generous.</h2></div><ToggleButton class="pin" pressed={pinned()} onChange={value=>{setPinned(value);setNotice(value?'Recipe pinned in this local preview.':'Recipe unpinned in this local preview.')}} aria-label="Pin recipe">{pinned()?'Pinned ✓':'Pin recipe'}</ToggleButton></div><p class="recipe-description">Sweet citrus, tender beans and crisp fennel. Use the checklist to gather the amounts for your chosen portion count.</p><div class="ingredient-title"><h3>Ingredients</h3><span>{checked().size} / 5 gathered</span></div><div class="ingredients"><For each={ingredients}>{ingredient=><Checkbox class="ingredient" checked={checked().has(ingredient.id)} onChange={value=>mark(ingredient.id,value)} disabled={!valid()}><Checkbox.Input/><Checkbox.Control class="check-control"><Checkbox.Indicator>✓</Checkbox.Indicator></Checkbox.Control><Checkbox.Label class="ingredient-label"><span>{ingredient.name}</span><strong>{valid()?ingredient.grams*portions()+' g':'—'}</strong></Checkbox.Label></Checkbox>}</For></div></section><aside class="portion-panel"><h2>Make it yours</h2><NumberField rawValue={portions()} onRawValueChange={update} minValue={1} maxValue={8} step={1} formatOptions={{maximumFractionDigits:0}} validationState={valid()?'valid':'invalid'} class="portion-field"><NumberField.Label class="field-label">Portions</NumberField.Label><div class="stepper"><NumberField.DecrementTrigger aria-label="Fewer portions">−</NumberField.DecrementTrigger><NumberField.Input/><NumberField.IncrementTrigger aria-label="More portions">+</NumberField.IncrementTrigger></div><NumberField.Description class="field-description">Choose 1–8 whole portions. Changing the quantity clears ingredient checks.</NumberField.Description><NumberField.ErrorMessage class="field-error">Enter a whole number from 1 to 8.</NumberField.ErrorMessage></NumberField><div class="portion-total"><span>Total ingredients</span><strong>{valid()?ingredients.reduce((s,x)=>s+x.grams,0)*portions()+' g':'—'}</strong></div><h3>A simple preparation order</h3><ol><li>Gather the scaled amounts and drain the cooked beans.</li><li>Combine the orange, fennel and leaves in a bowl.</li><li>Add the beans and dressing, then toss gently.</li></ol><button class="reset" onClick={reset}>Restore default recipe</button><p role="status" class="notice">{notice()||(pinned()?'Recipe pinned in this local preview.':'No shopping order or account update is created.')}</p></aside></div></main>
}

Référence du code

  • Utiliser le modèle Vite pour Solid, et non un compilateur JSX de React.
  • rawValue porte l’état numérique ; toutes les quantités d’ingrédients sont calculées à partir de ce signal.
  • Le changement du nombre de portions efface le Set des cases cochées, car les quantités précédentes ne sont plus à jour.

Configuration visuelle d’origine complète

Propriétés personnalisées sémantiques, hiérarchie typographique, espacement, styles d’état et illustration originale CSS.

css
:root{--recipe-canvas:#f6f2ec;--recipe-surface:#fffefa;--recipe-ink:#403a30;--recipe-muted:#807465;--recipe-line:#e6ded2;--recipe-action:#95612f;--recipe-on-action:#fff;--recipe-focus:#b88955;--recipe-soft:#f1e4d3;--recipe-space-1:4px;--recipe-space-2:8px;--recipe-space-3:12px;--recipe-space-4:16px;--recipe-space-6:24px;--recipe-space-8:32px}html,body,#app{height:auto;min-height:0;margin:0}*{box-sizing:border-box}body{font-family:system-ui,sans-serif;color:var(--recipe-ink);background:var(--recipe-canvas)}button,input{font:inherit}button{cursor:pointer}button:disabled{opacity:.4;cursor:default}button:focus-visible,input:focus-visible{outline:3px solid var(--recipe-focus);outline-offset:3px}.recipe-shell{max-width:1090px;margin:auto;padding:32px}.eyebrow{font-size:10px;font-weight:700;letter-spacing:.13em;color:var(--recipe-muted)}h1{font-size:34px;line-height:1.15;max-width:700px;margin:12px 0}header>p:last-child{font-size:14px;line-height:1.7;color:var(--recipe-muted);max-width:630px}.recipe-layout{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:24px;margin-top:28px}.recipe-card,.portion-panel{background:var(--recipe-surface);border:1px solid var(--recipe-line);border-radius:16px;padding:24px;min-width:0}.portion-panel{align-self:start}.salad-art{height:180px;background:#e8e4d5;border-radius:10px;position:relative;overflow:hidden;margin-bottom:24px}.plate{position:absolute;width:210px;height:210px;left:50%;top:18px;transform:translateX(-50%);border:18px solid #faf8f0;border-radius:50%;background:#dedcbf;box-shadow:0 10px 25px #5e584b1c}.plate i,.plate b,.plate em,.plate span,.plate strong{position:absolute;display:block}.plate i{width:85px;height:42px;border-radius:0 0 85px 85px;background:#dc9658;border:6px solid #f7c888;left:14px;top:18px;transform:rotate(-23deg)}.plate b{width:72px;height:36px;border-radius:0 0 72px 72px;background:#dc9658;border:6px solid #f7c888;left:75px;top:83px;transform:rotate(28deg)}.plate em{width:50px;height:77px;background:#83976a;border-radius:80% 0 80% 0;left:108px;top:4px;transform:rotate(20deg)}.plate span{width:30px;height:50px;background:#667f56;border-radius:80% 0 80% 0;left:25px;top:88px;transform:rotate(-23deg)}.plate strong{width:24px;height:34px;background:#fff3d7;border-radius:50%;left:80px;top:46px;box-shadow:-34px 14px 0 #fff3d7,25px 28px 0 #fff3d7}.recipe-heading{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.recipe-heading h2{font:400 30px/1.2 Georgia,serif;margin:8px 0}.pin{border:1px solid var(--recipe-line);background:white;border-radius:999px;padding:9px 13px;font-size:11px;color:var(--recipe-action)}.pin[data-pressed]{background:var(--recipe-soft);border-color:var(--recipe-action)}.recipe-description{font-size:13px;line-height:1.7;color:var(--recipe-muted)}.ingredient-title{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:24px}.ingredient-title h3{font-size:16px;margin:0}.ingredient-title span{font-size:11px;color:var(--recipe-muted)}.ingredients{margin-top:14px}.ingredient{display:flex;gap:12px;align-items:center;border-top:1px solid var(--recipe-line);padding:16px 0;cursor:pointer}.check-control{height:21px;width:21px;border:1px solid #b9ab98;border-radius:5px;flex-shrink:0;display:flex;justify-content:center;align-items:center;font-size:13px}.check-control[data-checked]{background:var(--recipe-action);color:white;border-color:var(--recipe-action)}.check-control[data-focus-visible]{outline:3px solid var(--recipe-focus);outline-offset:3px}.ingredient-label{display:flex;justify-content:space-between;gap:12px;width:100%;font-size:13px;line-height:1.5;cursor:pointer}.ingredient-label strong{white-space:nowrap;font-size:12px}.ingredient[data-checked] .ingredient-label>span{text-decoration:line-through;color:var(--recipe-muted)}.portion-panel>h2{font-size:20px;margin:0 0 24px}.field-label{font-size:13px;font-weight:600}.stepper{display:flex;margin-top:10px;border:1px solid var(--recipe-line);border-radius:8px;overflow:hidden}.stepper button{width:42px;flex-shrink:0;background:var(--recipe-soft);border:0;font-size:21px}.stepper input{width:100%;min-width:0;text-align:center;border:0;padding:12px 0;background:white;color:var(--recipe-ink)}.field-description{font-size:11px;line-height:1.7;color:var(--recipe-muted);margin:10px 0 0}.field-error{font-size:12px;color:#a73324}.portion-total{display:flex;justify-content:space-between;gap:12px;margin:24px 0;padding:18px 0;border-top:1px solid var(--recipe-line);border-bottom:1px solid var(--recipe-line);font-size:12px}.portion-total strong{font-size:19px;white-space:nowrap}.portion-panel h3{font-size:13px;line-height:1.6}.portion-panel ol{padding-left:18px;font-size:12px;line-height:1.7;color:var(--recipe-muted)}.portion-panel li{margin-bottom:12px}.reset{width:100%;padding:12px;border:1px solid var(--recipe-line);border-radius:8px;background:white;color:var(--recipe-action);font-size:12px;margin-top:16px}.notice{font-size:11px;line-height:1.7;color:var(--recipe-muted)}@media(max-width:760px){.recipe-layout{grid-template-columns:minmax(0,1fr)}.recipe-shell{padding:20px}h1{font-size:29px}}@media(max-width:360px){.recipe-shell{padding:14px}.recipe-card,.portion-panel{padding:16px}.ingredient-label{gap:8px;font-size:12px}.ingredient{gap:8px}.ingredient-label strong{font-size:11px}.recipe-heading h2{font-size:27px}}

Référence du code

  • Ces valeurs recipe-* sont des choix originaux propres à l’application, et non des tokens officiels de Kobalte.
  • La feuille de style complète comprend une composition adaptative et un indicateur de focus visible.
04

Système de design Kobalte Configuration de l’agent

Point de départ de l’implémentation

Le modèle Vite pour Solid fournit le compilateur JSX requis pour Solid. Les exemples complets App.jsx et style.css ci-dessus contiennent tout le code et les styles de l’application ; aucun fournisseur ni service externe n’est nécessaire.

javascript
// npm create vite@latest kobalte-recipe -- --template solid
// cd kobalte-recipe && npm install
// npm install [email protected] @kobalte/[email protected]
// Save the complete examples as src/App.jsx and src/style.css.
// src/index.jsx:
import {render} from 'solid-js/web';
import App from './App.jsx';
import './style.css';
render(() => <App />, document.getElementById('app'));
// index.html: <div id="app"></div><script type="module" src="/src/index.jsx"></script>
// npm run dev

Un prompt pour votre projet

Prompt pour l’agent IA
Utilisez Kobalte 0.13.14 avec Solid 1.9.15 pour reproduire la fiche recette réactive. Conservez NumberField rawValue/onRawValueChange, les limites de un à huit, la validation des portions entières et la structure complète Label/Description/ErrorMessage. Calculez les grammes d’ingrédients et les totaux à partir du signal des portions ; tout véritable changement de quantité efface le Set immuable des identifiants cochés, mais conserve l’épingle de la recette. Conservez les éléments natifs de Checkbox ainsi que ToggleButton pressed/onChange, désactivez le rassemblement des ingrédients lorsque la quantité est non valide et, lors de la réinitialisation, rétablissez quatre portions, aucune case cochée et aucune épingle. Incluez le fichier CSS original complet de la recette ; tout l’état reste local.
05

Kobalte Sources et périmètre du système de design

Vérifié avec Kobalte 0.13.14 et Solid 1.9.15. Tous les tokens recipe-*, l’illustration CSS et les quantités d’ingrédients sont des données originales de l’exemple. L’épinglage et le rassemblement des ingrédients restent des états locaux ; aucun compte, service d’achat ni espace de stockage de recettes persistant n’est connecté.