OpenUI : un langage compact pour laisser le modèle générer l'interface
The Open Standard for Generative UI
En bref
- De quoi s’agit-il ?
- OpenUI est un framework TypeScript sous licence MIT qui remplace la sortie texte d'un LLM par un langage structuré, OpenUI Lang, rendu progressivement côté client. Le point à vérifier avant d'adopter : la qualité du parseur face à un flux partiel.
- À qui s’adresse-t-il ?
- À adopter si vous avez déjà une bibliothèque de composants React et que vous voulez que le modèle compose l'interface plutôt que de la décrire. À écarter si vous ne pouvez pas faire transiter le flux brut jusqu'au client, ou si vous visez un rendu non interactif.
- Puis-je l’utiliser commercialement ?
- Oui. MIT est une licence permissive : vous pouvez utiliser, modifier et vendre un logiciel qui en dépend, à condition de conserver les mentions de droit d’auteur et de licence.
- Est-il encore maintenu ?
- Oui. Le dépôt a reçu de nouveaux commits au cours des dernières 24 heures.
- En quel langage est-il écrit ?
- Principalement TypeScript, d’après les statistiques de langage de GitHub.
Ces réponses reposent sur les données GitHub du projet (dernière synchronisation le 15 septembre 2026) et sur notre analyse. Elles ne constituent pas un avis juridique.
ANALYSE OPEN SOURCE APPROFONDIE
Le problème : un modèle qui décrit une interface au lieu de la produire
Un LLM branché sur une application de chat renvoie du texte. Si vous voulez qu'il affiche un tableau, un formulaire ou un graphique, il faut soit lui faire produire du JSON que vous interprétez, soit lui faire écrire du HTML que vous injectez. Les deux voies ont un coût. Le JSON est verbeux et se prête mal au streaming : tant que l'objet n'est pas complet, il n'est pas analysable. Le HTML donne au modèle un contrôle trop large sur le rendu et sur ce que l'utilisateur peut déclencher.
OpenUI prend un troisième chemin. Le README résume la boucle en cinq étapes : définir une bibliothèque de composants, générer un prompt système à partir de cette bibliothèque, envoyer ce prompt au modèle, recevoir un flux en OpenUI Lang, puis le rendre progressivement avec le Renderer. La cible est donc l'ingénieur qui construit un assistant ou un copilote et qui veut que la réponse soit une interface, pas une phrase. Le projet se présente comme un standard ouvert, avec un support React officiel et des intégrations Vue et Svelte décrites comme soutenues par la communauté.
OpenUI Lang : un format pensé pour le flux, pas pour le fichier
Le README avance qu'OpenUI Lang consomme jusqu'à 67 % de tokens en moins que JSON. C'est une affirmation du projet, pas une mesure indépendante, et elle dépend évidemment de la forme des données comparées. Ce qui est vérifiable dans le matériel fourni, c'est l'intention de conception : un langage compact, orienté streaming, où la sortie du modèle est un arbre de composants plutôt qu'un document à parser en une fois.
La conséquence pratique est double. D'abord, le coût par échange baisse, ce qui compte quand chaque rendu d'interface repart pour un tour de génération. Ensuite, et c'est le point structurant, le parseur doit accepter une entrée incomplète. Un flux arrive par morceaux ; à n'importe quel instant, le tampon contient un composant ouvert dont les attributs ne sont pas tous là. Un parseur JSON classique échoue dans cette situation. Le renderer d'OpenUI, lui, doit décider quoi afficher d'un composant à moitié reçu. C'est là que se joue la qualité perçue de l'ensemble, et le README ne détaille pas cette politique.
La bibliothèque de composants comme source du prompt
Le mécanisme central est la génération du prompt système depuis la bibliothèque de composants. Vous ne rédigez pas à la main la liste de ce que le modèle a le droit d'émettre : vous définissez des composants, et le framework en dérive les instructions. Le diagramme du README place la Component Library en amont du System Prompt, qui alimente le LLM, dont la sortie traverse le Renderer jusqu'à l'interface vivante.
Ce choix a une conséquence de gouvernance appréciable. La surface d'action du modèle est bornée par ce que vous avez déclaré. Si un composant n'est pas dans la bibliothèque, le modèle ne peut pas le produire, et le renderer n'a pas à exécuter du HTML arbitraire. En contrepartie, toute évolution de l'interface passe par une modification de la bibliothèque, donc par un redéploiement du prompt. Ajouter un bouton devient un changement de code, pas une instruction glissée dans une conversation. C'est plus sain, c'est aussi plus lourd.
Découpage des paquets : du parseur sans framework jusqu'aux surfaces de chat
Le dépôt est un monorepo TypeScript. La couche basse, @openuidev/lang-core, contient le parseur, la génération de prompt, l'évaluation à l'exécution et les types, sans dépendance à React, Vue ou Svelte. C'est le paquet à regarder en premier si vous voulez juger le projet sur son cœur technique plutôt que sur son habillage.
Au-dessus, @openuidev/react-lang sert à définir des bibliothèques de composants, générer les prompts et rendre le flux en React. @openuidev/react-headless fournit l'état de chat, les adaptateurs de streaming et les convertisseurs de messages pour qui apporte sa propre interface. @openuidev/react-ui vise le chemin le plus court vers un chat complet, avec des mises en page prêtes et deux bibliothèques de composants intégrées. Deux paquets sortent du cadre web classique : @openuidev/react-email pour générer des courriels et les exporter en HTML, et @openuidev/browser-bundle pour une utilisation via CDN. @openuidev/langchain cible les agents LangChain et LangGraph, avec un transformateur d'agent et des helpers serveur qui diffusent OpenUI via AG-UI. Vue et Svelte ont leurs propres liaisons.
Cette granularité est cohérente, mais elle impose de choisir tôt où l'on se situe. Prendre react-ui pour prototyper puis vouloir descendre vers react-headless n'est pas gratuit.
Mise en route : une commande, une clé, un serveur de développement
Le README donne une séquence de démarrage courte. On crée le projet avec le CLI, on entre dans le dossier, on écrit la clé dans un fichier .env, on lance le serveur de développement :
npx @openuidev/cli@latest create --name genui-chat-app cd genui-chat-app echo "OPENAI_API_KEY=sk-your-key-here" > .env npm run dev
L'application générée inclut le support d'OpenUI Lang, la génération de prompts depuis la bibliothèque autorisée, le streaming et une base d'application fonctionnelle. Le nom de la variable, OPENAI_API_KEY, indique que le fournisseur par défaut du modèle est OpenAI. Le matériel fourni ne précise pas comment basculer vers un autre fournisseur ni quelles variables seraient alors attendues. Un playground en ligne permet de tester la génération avec la bibliothèque de composants par défaut sans rien installer.
Là où le modèle casse : flux partiel, composants inconnus, serveur exposé
La difficulté propre à ce type de framework n'est pas le rendu d'un arbre complet, c'est le rendu d'un arbre en cours de construction. Un flux peut s'interrompre au milieu d'un attribut, ou produire un composant absent de la bibliothèque déclarée. Le README ne décrit pas le comportement dans ces cas : le composant est-il ignoré, rendu avec des valeurs par défaut, ou l'erreur remonte-t-elle au chat ? Impossible de le dire depuis le matériel fourni. C'est pourtant la question qui décide de la robustesse en production, et elle mérite un test avant tout engagement.
Deuxième point, le streaming suppose que les tokens traversent votre infrastructure jusqu'au navigateur. Si votre architecture impose une réponse complète avant affichage, l'avantage principal du projet disparaît et il ne reste qu'un format compact, ce qui ne justifie plus la dépendance.
Troisième point, la clé du modèle. La commande d'amorçage la place dans un fichier .env local, ce qui est normal pour un exemple, mais rien dans le matériel fourni ne décrit un proxy serveur ou une limitation de débit. Exposer une clé côté client est un problème que le projet ne traite pas dans sa documentation visible.
Face à une génération de JSON Schema imposée au modèle
L'alternative la plus directe consiste à garder JSON et à contraindre le décodage du modèle avec un schéma, en utilisant les modes structurés proposés par les fournisseurs. L'approche est bien outillée, les validateurs sont matures, et l'on reste dans un format que tout le monde lit. La différence tient au streaming. Un objet JSON n'est exploitable qu'une fois fermé, sauf à écrire un parseur tolérant aux coupures, ce que peu d'équipes font. OpenUI déplace ce travail dans le framework : le langage est conçu dès le départ pour être consommé par morceaux, et le renderer assume l'affichage progressif.
Le revers est l'écosystème. JSON Schema est un standard que vos outils connaissent déjà. OpenUI Lang est un format propre au projet, avec son parseur, ses types et ses conventions. Adopter OpenUI, c'est accepter qu'une partie de votre chaîne de génération dépende d'un format que vous ne pouvez pas remplacer par une bibliothèque générique.
Maintenance, licence et ce qui reste à vérifier
Le dépôt est publié sous MIT, ce qui autorise l'usage commercial, la modification et la redistribution, à condition de conserver l'avis de licence. Le matériel fourni ne mentionne aucune clause additionnelle ni aucun fichier de licence séparé pour les paquets individuels. Sur la maintenance, les éléments disponibles sont minces : la branche par défaut est main, le dernier push date du 9 septembre 2026, aucune release n'a été récupérée, et les topics incluent help-wanted et looking-for-contributors. Ce dernier point se lit comme un appel à contributeurs plutôt que comme la preuve d'une équipe nombreuse. Un pipeline de build est exposé pour le JavaScript. Rien ne permet d'estimer la fréquence des changements cassants dans les paquets @openuidev, et c'est précisément ce qu'il faut mesurer avant de s'y engager : l'historique des versions de lang-core et la stabilité de son API de parsing. Le README signale par ailleurs qu'aucun jeton ni crypto-actif n'est associé au projet, ce qui est une mise en garde contre les usurpations, pas une information technique.
Conclusion éditoriale
À adopter si vous avez déjà une bibliothèque de composants React et que vous voulez que le modèle compose l'interface plutôt que de la décrire. À écarter si vous ne pouvez pas faire transiter le flux brut jusqu'au client, ou si vous visez un rendu non interactif. Avant tout chose, vérifiez le parseur de @openuidev/lang-core sur une réponse tronquée en plein milieu d'un attribut, puis regardez les exemples de @openuidev/react-lang pour savoir si votre bibliothèque s'y projette sans réécriture.
Notes de la communauté