Styled Components — CSS in JS, props bilan dinamik stil
Muammodan boshlaylik
Tugma komponenti yozyapsiz. Uch xil variant kerak: oddiy, xavfli, o'chirilgan. CSS Modules bilan shunday qilasiz:
<button className={`${styles.btn} ${styles[variant]} ${disabled ? styles.disabled : ''}`}>
className satrini yig'ish uchun ternary, kvadrat qavslar, template literal — hammasi bitta qatorda. Hali size, fullWidth, loading variantlari qo'shilmagan.
Yana bir muammo: stil va mantiq ikki joyda — Button.jsx va Button.module.css. Qaysi klassning qaysi propga bog'liqligini ko'rish uchun ikki faylni birga ochib olishingiz kerak.
Styled Components bu ikki muammoni hal qiladi: stil to'g'ridan-to'g'ri komponent ichida, props orqali dinamik o'zgaradi.
Styled Components nima?
Styled Components — bu CSS ni JavaScript ichida yozish imkonini beradigan kutubxona. Siz oddiy HTML elementidan yoki mavjud komponentdan yangi stilizatsiya qilingan komponent yaratasiz.
Hayotiy o'xshatma: oddiy charm ko'rpa bor, siz uning ustiga maxsus qopqoq tikasiz — qizil, yumshoq, tugmali. Endi bu yangi narsa — ko'rpa emas, o'z nomi bor alohida buyum. Styled Components ham shunday: oddiy <button> dan yangi <PrimaryButton> yaratasiz — uning o'z stiliga ega, alohida komponent.
O'rnatish
npm install styled-components
TypeScript ishlatayotgan bo'lsangiz:
npm install styled-components
npm install -D @types/styled-components
Birinchi styled komponent
import styled from 'styled-components';
// styled.button — <button> elementidan yangi komponent yaratadi
const Button = styled.button`
background: #3b82f6;
color: white;
padding: 10px 20px;
border-radius: 6px;
border: none;
cursor: pointer;
font-size: 14px;
transition: background 0.2s;
&:hover {
background: #2563eb;
}
&:active {
transform: scale(0.98);
}
`;
// Ishlatish — oddiy HTML elementi kabi
function App() {
return <Button>Saqlash</Button>;
}
styled.button — tagged template literal. Backtick ` ichidagi matn CSS sifatida o'qiladi. & — bu komponentning o'zi, SCSS dagi & ga o'xshash.
Brauzerda Button oddiy <button> bo'ladi, lekin unga noyob klass qo'shilgan: class="sc-abc123 dXqPzL". CSS Modules ga o'xshash mexanizm — nom konflikti yo'q.
Props bilan dinamik stil — asosiy kuch
Bu Styled Components ning eng muhim xususiyati. Props ga qarab stil o'zgaradi.
const Button = styled.button`
padding: 10px 20px;
border-radius: 6px;
border: none;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
/* props.variant ga qarab fon rangi o'zgaradi */
background: ${props => {
if (props.variant === 'danger') return '#ef4444';
if (props.variant === 'success') return '#10b981';
return '#3b82f6'; // standart — primary
}};
color: white;
/* props.size ga qarab padding va shrift */
padding: ${props => props.size === 'sm' ? '6px 14px' : '10px 20px'};
font-size: ${props => props.size === 'sm' ? '13px' : '14px'};
/* props.fullWidth — boolean prop */
width: ${props => props.fullWidth ? '100%' : 'auto'};
/* props.disabled ga qarab opacity */
opacity: ${props => props.disabled ? 0.5 : 1};
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
&:hover {
filter: ${props => props.disabled ? 'none' : 'brightness(0.9)'};
}
`;
// Ishlatish
<Button>Oddiy</Button>
<Button variant="danger">O'chirish</Button>
<Button variant="success" size="sm">Saqlash</Button>
<Button fullWidth>Kirish</Button>
<Button disabled>Bloklangan</Button>
Nima uchun bu qulay? className yig'ish yo'q. Qaysi props qaysi stilga ta'sir qilishini bir joyda ko'rasiz. TypeScript bilan proplar aniq chegaralanadi.
Props ni HTMLga o'tkazmaslik
Styled Components props ni avtomatik HTML elementiga uzatadi. Lekin ba'zi proplar HTML atributi emas — brauzer console da ogohlantirish chiqadi.
// ❌ Muammo: variant, fullWidth HTML da mavjud emas
// Brauzer: Unknown prop `variant` on <button> tag
const Button = styled.button`
background: ${p => p.variant === 'danger' ? 'red' : 'blue'};
width: ${p => p.fullWidth ? '100%' : 'auto'};
`;
Yechim — $ prefiksi (styled-components v6 dan beri):
// ✅ $ bilan boshlanadigan props HTMLga o'tmaydi
const Button = styled.button`
background: ${p => p.$variant === 'danger' ? 'red' : 'blue'};
width: ${p => p.$fullWidth ? '100%' : 'auto'};
`;
<Button $variant="danger" $fullWidth>O'chirish</Button>
$variant, $fullWidth — faqat styled-components uchun, HTMLga yetib bormaydi.
Mavjud komponentni kengaytirish
Styled Components yordamida mavjud komponentni kengaytirish mumkin — uning stillarini meros olib, ustiga yangi qo'shish:
const Button = styled.button`
padding: 10px 20px;
border-radius: 6px;
border: none;
cursor: pointer;
background: #3b82f6;
color: white;
`;
// Button stillarini meros oladi, ustiga qo'shadi
const OutlineButton = styled(Button)`
background: transparent;
border: 1px solid #3b82f6;
color: #3b82f6;
&:hover {
background: #3b82f6;
color: white;
}
`;
const IconButton = styled(Button)`
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
`;
<Button>Asosiy</Button>
<OutlineButton>Chegarali</OutlineButton>
<IconButton>
<svg>...</svg>
Ikona bilan
</IconButton>
SCSS dagi @extend ga o'xshaydi — lekin komponent darajasida ishlaydi.
.attrs() — default atributlar
Komponentga default HTML atributlarini bir marta belgilash:
const Input = styled.input.attrs({
type: 'text',
autoComplete: 'off',
spellCheck: false,
})`
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 8px 12px;
font-size: 14px;
outline: none;
width: 100%;
&:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
`;
// Har safar type="text" yozish shart emas
<Input placeholder="Ism kiriting" />
<Input placeholder="Email" />
Props bilan ham ishlaydi:
const SizedInput = styled.input.attrs(props => ({
type: props.$type || 'text',
size: props.$size || 20, // HTML size atributi
}))`
padding: ${p => p.$size === 'lg' ? '12px 16px' : '8px 12px'};
`;
Animatsiya — keyframes
import styled, { keyframes } from 'styled-components';
// @keyframes o'rniga keyframes helper
const spin = keyframes`
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
`;
const fadeIn = keyframes`
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
`;
const Spinner = styled.div`
width: 24px;
height: 24px;
border: 3px solid #e5e7eb;
border-top-color: #3b82f6;
border-radius: 50%;
animation: ${spin} 0.8s linear infinite;
`;
const FadeCard = styled.div`
background: white;
border-radius: 8px;
padding: 20px;
animation: ${fadeIn} 0.3s ease;
`;
Tema (ThemeProvider)
Katta loyihalarda barcha komponentlar uchun bir xil ranglar, shriftlar, masofalarni boshqarish muammosi bor. ThemeProvider yechim beradi:
import { ThemeProvider } from 'styled-components';
const tema = {
ranglar: {
primary: '#3b82f6',
danger: '#ef4444',
success: '#10b981',
text: '#111827',
textMuted:'#6b7280',
border: '#e5e7eb',
bg: '#ffffff',
},
radius: {
sm: '4px',
md: '6px',
lg: '12px',
},
font: {
sm: '13px',
md: '14px',
lg: '16px',
},
};
// App ni ThemeProvider bilan o'rab olamiz
function App() {
return (
<ThemeProvider theme={tema}>
<Sahifa />
</ThemeProvider>
);
}
Endi har qanday styled komponent props.theme orqali temaga kiradi:
const Button = styled.button`
background: ${p => p.theme.ranglar.primary};
border-radius: ${p => p.theme.radius.md};
font-size: ${p => p.theme.font.md};
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
`;
const Card = styled.div`
background: ${p => p.theme.ranglar.bg};
border: 1px solid ${p => p.theme.ranglar.border};
border-radius: ${p => p.theme.radius.lg};
padding: 20px;
`;
const MutedText = styled.p`
color: ${p => p.theme.ranglar.textMuted};
font-size: ${p => p.theme.font.sm};
`;
Nima uchun tema kerak? Bir joyda primary rangini o'zgartirsangiz — barcha komponentlarda o'zgaradi. Dark mode qo'shish uchun yangi tema ob'ekti yaratib ThemeProvider ga bering — tamom.
Amaliy misol — to'liq Card komponenti
import styled, { keyframes } from 'styled-components';
const fadeUp = keyframes`
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
`;
const CardWrapper = styled.div`
background: white;
border: 1px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
animation: ${fadeUp} 0.3s ease;
transition: box-shadow 0.2s, transform 0.2s;
&:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
transform: translateY(-2px);
}
`;
const CardImage = styled.img`
width: 100%;
height: 200px;
object-fit: cover;
display: block;
`;
const CardBody = styled.div`
padding: 16px;
`;
const CardTitle = styled.h3`
font-size: 16px;
font-weight: 600;
color: #111827;
margin-bottom: 6px;
`;
const CardText = styled.p`
font-size: 14px;
color: #6b7280;
line-height: 1.6;
margin-bottom: 16px;
`;
const CardFooter = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 12px;
border-top: 1px solid #f3f4f6;
`;
const Tag = styled.span`
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 3px 8px;
border-radius: 20px;
/* $color prop ga qarab dinamik stil */
background: ${p => p.$color ? `${p.$color}18` : '#f3f4f6'};
color: ${p => p.$color || '#6b7280'};
`;
const ReadButton = styled.button`
font-size: 13px;
color: #3b82f6;
background: none;
border: none;
cursor: pointer;
padding: 0;
font-weight: 500;
&:hover {
text-decoration: underline;
}
`;
// Ishlatish
function ArticleCard({ article }) {
return (
<CardWrapper>
<CardImage src={article.image} alt={article.title} />
<CardBody>
<CardTitle>{article.title}</CardTitle>
<CardText>{article.excerpt}</CardText>
<CardFooter>
<Tag $color="#3b82f6">{article.category}</Tag>
<ReadButton>O'qish →</ReadButton>
</CardFooter>
</CardBody>
</CardWrapper>
);
}
Fayl tuzilishi aniq: har bir vizual element o'z nomiga ega komponent. CardImage, CardBody, CardFooter — JSX o'qilganda tuzilish darhol ko'rinadi.
Tez-tez uchraydigan xatolar
Props HTMLga o'tib ketishi
// ❌ variant HTML da mavjud emas — console da ogohlantirish
const Box = styled.div`
color: ${p => p.variant === 'red' ? 'red' : 'blue'};
`;
<Box variant="red">...</Box>
// ✅ $ prefiksi ishlatish
const Box = styled.div`
color: ${p => p.$variant === 'red' ? 'red' : 'blue'};
`;
<Box $variant="red">...</Box>
Render ichida styled komponent yaratish
// ❌ Har render da yangi klass yaratiladi — juda sekin
function Component() {
const Title = styled.h1` font-size: 24px; `; // ← bu yerda emas!
return <Title>Salom</Title>;
}
// ✅ Komponentdan tashqarida bir marta yarating
const Title = styled.h1` font-size: 24px; `;
function Component() {
return <Title>Salom</Title>;
}
Bu eng ko'p uchraydigan xato. Komponent har render qilganda yangi CSS klassi yaratiladi — sahifa sekinlashadi, DevTools da yuzlab klaslar to'planib ketadi.
Haddan tashqari nesting
// ❌ Yomon — hamma narsa bitta katta styled komponentda
const Card = styled.div`
padding: 20px;
h3 {
font-size: 18px;
span {
color: red;
strong { font-weight: 900; }
}
}
p { color: gray; }
button { background: blue; }
`;
// ✅ Yaxshi — har element o'z komponenti
const Card = styled.div` padding: 20px; `;
const CardTitle = styled.h3` font-size: 18px; `;
const CardText = styled.p` color: gray; `;
CSS Modules dan farqli — Styled Components da element nomlari JSX da ko'rinadi. Bu afzallikdan foydalaning.
Styled Components vs CSS Modules
Styled Components:
+ Props bilan dinamik stil — juda qulay
+ Tema tizimi (ThemeProvider) — dark mode oson
+ Komponent va stil bir joyda
+ Fayllar alohida emas
- Runtime xarajat bor (kichik, lekin bor)
- Paket hajmi: ~12KB gzip
- Server Side Rendering — qo'shimcha sozlash kerak
CSS Modules:
+ Zero runtime — build vaqtida hal bo'ladi
+ Oddiy CSS — yangi sintaksis yo'q
+ Server Side Rendering — muammosiz
- Dinamik stil — className yig'ish kerak
- Tema tizimi — CSS variables bilan qo'lda
Kichik-o'rta loyihalarda ikkalasi ham yaxshi ishlaydi. Ko'p dinamik stil kerak bo'lsa — Styled Components. Maksimal performance va oddiylik kerak bo'lsa — CSS Modules.
Xulosa
Styled Components — CSS ni komponent ichida, props orqali dinamik boshqarish imkonini beradi. Klass nomlari avtomatik noyob bo'ladi, nom konflikti yo'q.
Eslab qoling:
styled.div,styled.button— HTML elementdan komponent yaratishstyled(Component)`— mavjud komponentni kengaytirish${p => p.$variant}— props bilan dinamik stil$prefiksi — props HTMLga o'tmasligi uchun.attrs()— default atributlar belgilashkeyframes— animatsiya yaratishThemeProvider— global tema tizimi- Styled komponentni render tashqarisida e'lon qilish
Keyingi dars
37-dars: Tailwind CSS — React bilan sozlash, classNames kutubxonasi