Meta has released Astryx, an open source design system that is fully customizable and built to be operated by both people and the AI agents working alongside them. It is available now in Beta. Astryx is not a new experiment. It grew inside Meta over the last eight years, where the company says it became its most-used and largest design system, shaped by the engineers, designers, and product teams who depend on it daily.
The system ships 150+ accessible components (the docs site now lists 160+), brand-level theming, dark mode, ready-to-ship templates, and a CLI as one cohesive package. It is built on React and StyleX. You import pre-built CSS and use typed React components. There is no build plugin to wire up and no styling library to adopt.
The trade-off Astryx is trying to remove
Most design systems force a choice. Adopt a large company’s system and your app tends to look like someone else’s product. Reach for copy-paste components instead and every project forks its own snippets, with no shared coherence, no upstream fixes, and accessibility quietly becoming your problem.
Astryx separates the two concerns. The system controls behavior, accessibility, and quality. Themes control how it looks. You customize at the token level (color, type, radius, motion) so the app becomes unmistakably yours without rewrites. A theme is simply a set of CSS custom property overrides, so a designer can retheme Astryx without forking or wrapping component source.
Its stated design principles are guidance over enforcement, strong documented conventions, one system for humans and AI, and earned by measurement — conventions are tested, not asserted.
Architecture: foundations, components, patterns
Astryx is organized in three layers. Foundations are the primitives for cohesive, accessible interfaces: typography, color, layout, and accessibility. Components are the 150+ reusable building blocks, all with full TypeScript support. Patterns are battle-tested solutions for common workflows: table pages, detail layouts, form wizards, navigation, and data-entry flows.
Two design decisions make it unusually open. Components are composed at any level rather than locked behind a closed top-level API, and swizzle can eject a component’s full source into your project when you need to own it. Styling is created with StyleX but stays invisible to consumers, so you can override with className using Tailwind, CSS modules, or plain CSS — whatever the project already uses. The explainer below shows how one set of components restyles across Astryx’s seven shipped themes when only the tokens change.
Astryx Explainer — Marktechpost
/* ===== Marktechpost · Astryx Interactive Explainer (LIGHT THEME) ===== */
#mtp-ax-explainer *{box-sizing:border-box;margin:0;padding:0}
#mtp-ax-explainer{
–ink:#16181D; –ink-2:#5A6270; –ink-3:#8A9099;
–line:#E6E8EC; –paper:#FFFFFF; –tint:#F6F7F9;
–brand:#1657E0; –brand-ink:#0B3AA8; –ok:#16A34A;
–mono:ui-monospace,”SF Mono”,”JetBrains Mono”,Menlo,Consolas,monospace;
–sans:”Inter Tight”,Inter,-apple-system,BlinkMacSystemFont,”Segoe UI”,system-ui,sans-serif;
font-family:var(–sans); color:var(–ink); background:var(–paper);
line-height:1.5; -webkit-font-smoothing:antialiased;
border:1px solid var(–line); border-radius:16px; overflow:hidden;
max-width:900px; margin:0 auto;
}
#mtp-ax-explainer .ax-head{padding:22px 24px 18px;border-bottom:1px solid var(–line);background:
linear-gradient(180deg,#FBFCFE,#FFFFFF)}
#mtp-ax-explainer .ax-eyebrow{font-family:var(–mono);font-size:11px;letter-spacing:.14em;
text-transform:uppercase;color:var(–brand);font-weight:600;display:flex;align-items:center;gap:8px}
#mtp-ax-explainer .ax-eyebrow::before{content:””;width:22px;height:2px;background:var(–brand);border-radius:2px}
#mtp-ax-explainer h2.ax-title{font-size:22px;line-height:1.2;letter-spacing:-.02em;margin:10px 0 4px;font-weight:700}
#mtp-ax-explainer .ax-sub{color:var(–ink-2);font-size:14px;max-width:60ch}
/* stat band */
#mtp-ax-explainer .ax-stats{display:grid;grid-template-columns:repeat(6,1fr);gap:1px;background:var(–line);
border-bottom:1px solid var(–line)}
#mtp-ax-explainer .ax-stat{background:var(–paper);padding:14px 12px;text-align:center}
#mtp-ax-explainer .ax-stat b{display:block;font-size:20px;letter-spacing:-.02em;font-weight:700;color:var(–ink)}
#mtp-ax-explainer .ax-stat span{display:block;font-family:var(–mono);font-size:10px;letter-spacing:.06em;
text-transform:uppercase;color:var(–ink-3);margin-top:3px}
#mtp-ax-explainer .ax-body{padding:22px 24px 8px}
#mtp-ax-explainer .ax-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:22px;align-items:start}
/* controls */
#mtp-ax-explainer .ax-panel h3{font-size:12px;font-family:var(–mono);letter-spacing:.08em;text-transform:uppercase;
color:var(–ink-2);margin-bottom:10px;font-weight:600}
#mtp-ax-explainer .ax-themes{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:18px}
#mtp-ax-explainer .ax-chip{cursor:pointer;border:1px solid var(–line);background:var(–paper);
border-radius:999px;padding:6px 12px 6px 8px;font-size:13px;font-weight:500;display:flex;align-items:center;gap:7px;
transition:border-color .15s,box-shadow .15s,transform .06s;color:var(–ink)}
#mtp-ax-explainer .ax-chip:hover{border-color:#C9CED6}
#mtp-ax-explainer .ax-chip .dot{width:14px;height:14px;border-radius:50%;box-shadow:inset 0 0 0 1px rgba(0,0,0,.08)}
#mtp-ax-explainer .ax-chip[aria-pressed=”true”]{border-color:var(–brand);
box-shadow:0 0 0 3px rgba(22,87,224,.12)}
#mtp-ax-explainer .ax-chip:focus-visible{outline:2px solid var(–brand);outline-offset:2px}
#mtp-ax-explainer .ax-sliders{display:grid;gap:14px;margin-bottom:16px}
#mtp-ax-explainer .ax-slider label{display:flex;justify-content:space-between;font-size:13px;color:var(–ink-2);margin-bottom:6px}
#mtp-ax-explainer .ax-slider label b{font-family:var(–mono);color:var(–ink);font-weight:600}
#mtp-ax-explainer input[type=range]{width:100%;accent-color:var(–brand);height:4px;cursor:pointer}
#mtp-ax-explainer .ax-toggle{display:inline-flex;align-items:center;gap:9px;font-size:13px;color:var(–ink-2);cursor:pointer;user-select:none}
#mtp-ax-explainer .ax-sw{width:38px;height:22px;border-radius:999px;background:#D5D9E0;position:relative;transition:background .18s}
#mtp-ax-explainer .ax-sw::after{content:””;position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;
background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .18s}
#mtp-ax-explainer .ax-toggle[aria-pressed=”true”] .ax-sw{background:var(–brand)}
#mtp-ax-explainer .ax-toggle[aria-pressed=”true”] .ax-sw::after{transform:translateX(16px)}
/* tokens readout */
#mtp-ax-explainer .ax-tokenbtn{margin-top:6px;font-family:var(–mono);font-size:12px;color:var(–brand);
background:none;border:none;cursor:pointer;padding:4px 0;text-decoration:underline;text-underline-offset:3px}
#mtp-ax-explainer .ax-tokens{margin-top:10px;background:#0E1116;border-radius:10px;padding:12px 14px;
font-family:var(–mono);font-size:12px;line-height:1.7;color:#C9D3E0;display:none;overflow-x:auto}
#mtp-ax-explainer .ax-tokens.show{display:block}
#mtp-ax-explainer .ax-tokens .k{color:#7FA6FF}
#mtp-ax-explainer .ax-tokens .v{color:#89E0B0}
/* live preview device */
#mtp-ax-explainer .ax-previewwrap{position:sticky;top:8px}
#mtp-ax-explainer .ax-device{border:1px solid var(–pv-line,#E6E8EC);border-radius:calc(var(–pv-radius,10px) + 6px);
background:var(–pv-bg,#fff);padding:16px;transition:background .25s,border-color .25s,border-radius .25s;
box-shadow:0 10px 30px -18px rgba(16,24,40,.35)}
#mtp-ax-explainer .ax-devbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
#mtp-ax-explainer .ax-devdots{display:flex;gap:5px}
#mtp-ax-explainer .ax-devdots i{width:8px;height:8px;border-radius:50%;background:var(–pv-line,#E6E8EC);display:block}
#mtp-ax-explainer .ax-devtag{font-family:var(–mono);font-size:10px;color:var(–pv-muted,#8A9099);letter-spacing:.05em}
#mtp-ax-explainer .ax-card{background:var(–pv-surface,#F4F4F5);border:1px solid var(–pv-line,#E6E8EC);
border-radius:var(–pv-radius,10px);overflow:hidden;transition:all .25s}
#mtp-ax-explainer .ax-thumb{height:96px;background:
linear-gradient(135deg,var(–pv-primary,#18181B),color-mix(in srgb,var(–pv-primary,#18181B) 55%,#ffffff));
position:relative}
#mtp-ax-explainer .ax-badge{position:absolute;top:10px;left:10px;background:var(–pv-bg,#fff);color:var(–pv-primary,#18181B);
font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:4px 8px;border-radius:999px}
#mtp-ax-explainer .ax-cardbody{padding:var(–pv-pad,14px)}
#mtp-ax-explainer .ax-cardbody h4{color:var(–pv-text,#18181B);font-size:15px;font-weight:700;margin-bottom:2px}
#mtp-ax-explainer .ax-cardbody p{color:var(–pv-muted,#6B7280);font-size:12.5px;margin-bottom:12px}
#mtp-ax-explainer .ax-row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:12px}
#mtp-ax-explainer .ax-price{color:var(–pv-text,#18181B);font-weight:700;font-size:15px}
#mtp-ax-explainer .ax-input{flex:1;border:1px solid var(–pv-line,#E6E8EC);background:var(–pv-bg,#fff);
border-radius:calc(var(–pv-radius,10px) – 2px);padding:8px 10px;font-size:12.5px;color:var(–pv-text,#18181B);min-width:0}
#mtp-ax-explainer .ax-input::placeholder{color:var(–pv-muted,#9AA0AA)}
#mtp-ax-explainer .ax-btn{background:var(–pv-primary,#18181B);color:var(–pv-onprimary,#fff);border:none;
border-radius:calc(var(–pv-radius,10px) – 2px);padding:9px 14px;font-size:13px;font-weight:600;cursor:pointer;
font-family:var(–sans);white-space:nowrap;transition:filter .15s}
#mtp-ax-explainer .ax-btn:hover{filter:brightness(.94)}
#mtp-ax-explainer .ax-btn.ghost{background:transparent;color:var(–pv-primary,#18181B);
box-shadow:inset 0 0 0 1px var(–pv-primary,#18181B)}
#mtp-ax-explainer .ax-mini{display:flex;align-items:center;gap:8px;color:var(–pv-muted,#6B7280);font-size:12px}
#mtp-ax-explainer .ax-miniSw{width:32px;height:19px;border-radius:999px;background:var(–pv-primary,#18181B);position:relative;flex:none}
#mtp-ax-explainer .ax-miniSw::after{content:””;position:absolute;top:2px;right:2px;width:15px;height:15px;border-radius:50%;background:var(–pv-bg,#fff)}
#mtp-ax-explainer .ax-caption{margin-top:10px;font-size:11.5px;color:var(–ink-3);text-align:center;font-style:italic}
/* architecture */
#mtp-ax-explainer .ax-arch{margin:6px 24px 4px;border-top:1px solid var(–line);padding-top:18px}
#mtp-ax-explainer .ax-arch h3{font-size:12px;font-family:var(–mono);letter-spacing:.08em;text-transform:uppercase;color:var(–ink-2);margin-bottom:12px;font-weight:600}
#mtp-ax-explainer .ax-layers{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
#mtp-ax-explainer .ax-layer{cursor:pointer;border:1px solid var(–line);border-radius:12px;padding:14px;background:var(–tint);
transition:border-color .15s,background .15s;text-align:left}
#mtp-ax-explainer .ax-layer:hover{border-color:#C9CED6}
#mtp-ax-explainer .ax-layer[aria-expanded=”true”]{border-color:var(–brand);background:#fff;box-shadow:0 0 0 3px rgba(22,87,224,.1)}
#mtp-ax-explainer .ax-layer .n{font-family:var(–mono);font-size:11px;color:var(–brand);font-weight:600}
#mtp-ax-explainer .ax-layer b{display:block;font-size:14px;margin:4px 0 0}
#mtp-ax-explainer .ax-layer .desc{font-size:12.5px;color:var(–ink-2);margin-top:8px;max-height:0;overflow:hidden;transition:max-height .25s;line-height:1.5}
#mtp-ax-explainer .ax-layer[aria-expanded=”true”] .desc{max-height:120px}
/* footer */
#mtp-ax-explainer .ax-foot{margin-top:16px;border-top:1px solid var(–line);padding:12px 24px;
display:flex;align-items:center;justify-content:space-between;gap:10px;background:var(–tint);flex-wrap:wrap}
#mtp-ax-explainer .ax-foot a{color:var(–brand);text-decoration:none;font-weight:600}
#mtp-ax-explainer .ax-foot a:hover{text-decoration:underline}
#mtp-ax-explainer .ax-brand{font-size:11.5px;color:var(–ink-3)}
#mtp-ax-explainer .ax-brand b{color:#0B8A00;font-weight:700}
@media (max-width:680px){
#mtp-ax-explainer .ax-grid{grid-template-columns:1fr}
#mtp-ax-explainer .ax-stats{grid-template-columns:repeat(3,1fr)}
#mtp-ax-explainer .ax-layers{grid-template-columns:1fr}
#mtp-ax-explainer .ax-previewwrap{position:static}
}
@media (prefers-reduced-motion:reduce){#mtp-ax-explainer *{transition:none!important}}
Interactive explainer
One system, many skins: how Astryx splits behavior from brand
The components below never change. Only the tokens do. Pick a theme, drag the sliders, and watch the same accessible React UI restyle with no rewrites.
8 yrsIn production
13,000+Apps at Meta
150+Components
7Themes
MITLicense
React 19+ StyleX
1 · Choose a theme
2 · Tune the tokens
Corner radius 10px
Density (padding) 14px
Dark mode (built in)
▸ Show the tokens this theme sets
theme: neutral
New
Minimalist watch
Clean design, everyday durability.
$248
In stock
Apply
Add to cart
Same markup, same behavior — restyled only through CSS custom properties.
Under the hood · three layers
01Foundations
02Components
03Patterns
Explore the real themes →
Interactive explainer · palettes shown are representative · Marktechpost
(function(){
var root=document.getElementById(‘mtp-ax-explainer’);
// Representative token sets that mirror Astryx’s seven shipped themes.
var THEMES={
neutral:{label:’neutral’,primary:’#18181B’,onp:’#ffffff’,bg:’#ffffff’,surface:’#F4F4F5′,text:’#18181B’,muted:’#6B7280′,line:’#E4E4E7′,radius:10,dot:’#18181B’},
butter:{label:’butter’,primary:’#B7791F’,onp:’#ffffff’,bg:’#FFFEF6′,surface:’#FEF7C7′,text:’#422006′,muted:’#8A6D2F’,line:’#F3E4A8′,radius:16,dot:’#EAB308′},
chocolate:{label:’chocolate’,primary:’#7C4A2D’,onp:’#ffffff’,bg:’#FBF7F4′,surface:’#EFE3D8′,text:’#3B241A’,muted:’#8A6B58′,line:’#E3D2C4′,radius:6,dot:’#7C4A2D’},
matcha:{label:’matcha’,primary:’#3F7A3F’,onp:’#ffffff’,bg:’#F7FAF4′,surface:’#E6F0DF’,text:’#233620′,muted:’#5C7A55′,line:’#D4E4CB’,radius:12,dot:’#4E9A4E’},
stone:{label:’stone’,primary:’#475569′,onp:’#ffffff’,bg:’#FAFAFB’,surface:’#EEF0F3′,text:’#1F2937′,muted:’#64748B’,line:’#E2E6EC’,radius:8,dot:’#64748B’},
gothic:{label:’gothic’,primary:’#111111′,onp:’#ffffff’,bg:’#ffffff’,surface:’#ECECEC’,text:’#111111′,muted:’#555555′,line:’#111111′,radius:2,dot:’#111111′},
y2k:{label:’y2k’,primary:’#C026D3′,onp:’#ffffff’,bg:’#FBF4FF’,surface:’#FBE4FF’,text:’#4A044E’,muted:’#8B3FA0′,line:’#F0C7FA’,radius:22,dot:’#C026D3′}
};
var order=[‘neutral’,’butter’,’chocolate’,’matcha’,’stone’,’gothic’,’y2k’];
var current=’neutral’, dark=false;
var device=document.getElementById(‘axDevice’);
var devtag=document.getElementById(‘axDevTag’);
var tokensEl=document.getElementById(‘axTokens’);
var radius=document.getElementById(‘axRadius’), pad=document.getElementById(‘axPad’);
var radiusV=document.getElementById(‘axRadiusV’), padV=document.getElementById(‘axPadV’);
// build theme chips
var wrap=document.getElementById(‘axThemes’);
order.forEach(function(key){
var t=THEMES[key];
var b=document.createElement(‘button’);
b.className=’ax-chip’; b.type=’button’;
b.setAttribute(‘aria-pressed’, key===current?’true’:’false’);
b.innerHTML=”+t.label;
b.addEventListener(‘click’,function(){ current=key; radius.value=t.radius; sync(); });
wrap.appendChild(b);
});
function darken(hex,amt){ // mix hex toward black
var c=hex.replace(‘#’,”); var n=parseInt(c,16);
var r=(n>>16)&255,g=(n>>8)&255,bl=n&255;
r=Math.round(r*(1-amt)); g=Math.round(g*(1-amt)); bl=Math.round(bl*(1-amt));
return ‘rgb(‘+r+’,’+g+’,’+bl+’)’;
}
function sync(){
var t=THEMES[current];
radiusV.textContent=radius.value; padV.textContent=pad.value;
var s=device.style;
var bg = dark? ‘#15171C’ : t.bg;
var surface = dark? ‘#20242C’ : t.surface;
var text = dark? ‘#F4F5F7’ : t.text;
var muted = dark? ‘#A2AAB6’ : t.muted;
var line = dark? ‘#2C313B’ : t.line;
s.setProperty(‘–pv-bg’,bg);
s.setProperty(‘–pv-surface’,surface);
s.setProperty(‘–pv-text’,text);
s.setProperty(‘–pv-muted’,muted);
s.setProperty(‘–pv-line’,line);
s.setProperty(‘–pv-primary’,t.primary);
s.setProperty(‘–pv-onprimary’,t.onp);
s.setProperty(‘–pv-radius’,radius.value+’px’);
s.setProperty(‘–pv-pad’,pad.value+’px’);
devtag.textContent=’theme: ‘+t.label+(dark?’ · dark’:”);
// chips
Array.prototype.forEach.call(wrap.children,function(ch,i){
ch.setAttribute(‘aria-pressed’, order[i]===current?’true’:’false’);
});
// tokens readout
tokensEl.innerHTML=
‘–color-primary: ‘+t.primary+’;n’+
‘–color-background: ‘+bg+’;n’+
‘–color-surface: ‘+surface+’;n’+
‘–color-text-primary: ‘+text+’;n’+
‘–radius-container: ‘+radius.value+’px;n’+
‘–spacing-pad: ‘+pad.value+’px;n’+
‘–color-scheme: ‘+(dark?’dark’:’light’)+’;’;
}
radius.addEventListener(‘input’,sync);
pad.addEventListener(‘input’,sync);
var darkBtn=document.getElementById(‘axDark’);
darkBtn.addEventListener(‘click’,function(){ dark=!dark; darkBtn.setAttribute(‘aria-pressed’,dark?’true’:’false’); sync(); });
var tokBtn=document.getElementById(‘axTokBtn’);
tokBtn.addEventListener(‘click’,function(){
var open=tokensEl.classList.toggle(‘show’);
tokBtn.setAttribute(‘aria-expanded’,open?’true’:’false’);
tokBtn.textContent=(open?’▾’:’▸’)+’ ‘+(open?’Hide the tokens this theme sets’:’Show the tokens this theme sets’);
});
// architecture accordion
var layers=document.querySelectorAll(‘#axLayers .ax-layer’);
layers.forEach(function(l){
l.querySelector(‘.desc’).textContent=l.getAttribute(‘data-desc’);
l.addEventListener(‘click’,function(){
var open=l.getAttribute(‘aria-expanded’)===’true’;
layers.forEach(function(x){x.setAttribute(‘aria-expanded’,’false’);});
l.setAttribute(‘aria-expanded’, open?’false’:’true’);
});
});
// count-up stats
var reduce=window.matchMedia&&window.matchMedia(‘(prefers-reduced-motion:reduce)’).matches;
function countUp(el){
var target=+el.getAttribute(‘data-count’), suffix=el.getAttribute(‘data-suffix’)||”;
if(reduce){ el.textContent=target.toLocaleString()+suffix; return; }
var start=null,dur=900;
function step(ts){ if(!start)start=ts; var p=Math.min((ts-start)/dur,1);
var val=Math.floor((1-Math.pow(1-p,3))*target);
el.textContent=val.toLocaleString()+suffix; if(p

