What is a CSS type selector
A CSS type selector targets elements by their tag name. It’s also commonly called an element selector or tag selector.
Examples:
ptargets every<p>on the page.h2targets every<h2>.buttontargets every<button>.
Type selectors are often your first step into CSS because they’re simple and readable. But they’re also easy to overuse, which can lead to “why is everything styled?!” moments.
p {
color: #0b5fff;
}
h2 {
color: #b10f2e;
}
button {
background: #111;
color: #fff;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: ui-monospace, system-ui, sans-serif;
padding: 16px;
border: 2px solid #111;
border-radius: 12px;
display: grid;
gap: 12px;
max-width: 620px;
}
button {
border: 0;
padding: 10px 14px;
border-radius: 10px;
cursor: pointer;
}
h2 {
margin: 0;
font-size: 20px;
}
p {
margin: 0;
line-height: 1.45;
}
Type selectors target tags
This paragraph is a <p> element.
This is another <p> element.
In that playground, each snippet targets a different tag name. No classes. No IDs. Just the element type.
Your first type selectors
Let’s style a tiny “mini page” using only type selectors. This will show you both the power and the danger: it’s very easy to style a lot of elements very quickly.
h1 {
font-size: 28px;
letter-spacing: 0.02em;
}
p {
line-height: 1.6;
}
a {
color: #0b5fff;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
}
button {
background: #111;
color: #fff;
}
a {
color: #0b5fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
button {
background: #0b5fff;
color: #fff;
}
*,
::before,
::after {
box-sizing: border-box;
}
.page {
font-family: system-ui, ui-monospace, sans-serif;
max-width: 720px;
padding: 18px;
border: 2px solid #111;
border-radius: 14px;
}
h1 {
margin: 0;
}
p {
margin: 0;
}
.stack {
display: grid;
gap: 12px;
margin-top: 10px;
}
button {
border: 0;
padding: 10px 14px;
border-radius: 10px;
cursor: pointer;
width: fit-content;
}
Welcome to Tiny Page Land
This is a paragraph with a link inside it.
Another paragraph, because paragraphs like company.
Type selectors are great when you want consistent base styles. But if you style p globally, you’re
styling every paragraph everywhere. That’s why you’ll often see type selectors used for “defaults” and then
more specific selectors used for special cases.
Grouping type selectors with commas
If multiple element types should share the same rules, group them using commas.
h1, h2, h3targets all three heading types.input, textarea, selecttargets all those form controls.
h2,
h3 {
color: #0b5fff;
}
h2,
h3 {
border-left: 6px solid #111;
padding-left: 10px;
}
p,
li {
line-height: 1.7;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: system-ui, ui-monospace, sans-serif;
padding: 16px;
border: 2px solid #111;
border-radius: 14px;
max-width: 720px;
}
h2,
h3 {
margin: 0;
}
p {
margin: 10px 0 0;
}
ul {
margin: 10px 0 0;
padding-left: 22px;
}
li {
margin: 6px 0;
}
Grouped heading styles
This is an h3
This is a paragraph.
- This is a list item.
- So is this.
Grouping is mostly about keeping your CSS shorter and easier to maintain. If you catch yourself copy-pasting the same rules across multiple selectors, commas are your friend.
Combining type selectors with classes and IDs
You can combine a type selector with a class or ID to be more specific:
p.notemeans “paragraphs that have the classnote”.button.primarymeans “buttons with the classprimary”.p#intromeans “the paragraph with the IDintro”.
This is one of the best ways to avoid styling the entire universe when you only wanted to style one galaxy.
p.note {
background: #fff2c2;
padding: 10px 12px;
border-radius: 12px;
}
button.primary {
background: #0b5fff;
color: #fff;
}
p#intro {
font-weight: 700;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: system-ui, ui-monospace, sans-serif;
padding: 16px;
border: 2px solid #111;
border-radius: 14px;
display: grid;
gap: 12px;
max-width: 720px;
}
p {
margin: 0;
line-height: 1.6;
}
button {
border: 0;
padding: 10px 14px;
border-radius: 10px;
cursor: pointer;
width: fit-content;
background: #111;
color: #fff;
}
I am the intro paragraph.
This is just a normal paragraph.
This paragraph has the class "note".
Notice how p.note is safer than p if you only want “note styling” sometimes. It won’t touch
every paragraph on the site.
Descendant vs child with type selectors
Type selectors become much more useful when you combine them with relationships.
Descendant selector
nav a means “any link inside a <nav>, at any depth.”
Child selector
nav > a means “links that are direct children of <nav>.”
Learn more about the > selector in the CSS Direct Child Selector (>)
Interactive Tutorial.
nav a {
color: #0b5fff;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
}
nav > a {
background: #111;
color: #fff;
padding: 6px 10px;
border-radius: 999px;
text-decoration: none;
}
nav ul a {
font-style: italic;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: system-ui, ui-monospace, sans-serif;
padding: 16px;
border: 2px solid #111;
border-radius: 14px;
max-width: 760px;
display: grid;
gap: 12px;
}
nav {
border: 2px dashed #777;
padding: 12px;
border-radius: 12px;
display: grid;
gap: 10px;
}
nav a {
color: #111;
}
ul {
margin: 0;
padding-left: 18px;
}
li {
margin: 6px 0;
}
Outside the nav: this link should not be affected by nav selectors.
Play with the snippets and watch which links get targeted. This is where type selectors start feeling like real “targeting tools,” not just “style every paragraph ever.”
Multiple type selectors in a chain
You can chain type selectors together to describe a structure.
article h2targets headings inside an article.article ptargets paragraphs inside an article.article atargets links inside an article.
This is a gentle way to “scope” styles without needing a million extra classes.
article h2 {
color: #0b5fff;
}
article p {
line-height: 1.7;
}
article a {
color: #b10f2e;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.layout {
font-family: system-ui, ui-monospace, sans-serif;
display: grid;
gap: 14px;
max-width: 820px;
}
article,
aside {
border: 2px solid #111;
border-radius: 14px;
padding: 14px;
}
h2 {
margin: 0;
font-size: 20px;
color: #111;
}
p {
margin: 10px 0 0;
}
a {
color: #111;
}
Article heading
Article paragraph with an article link.
Notice how we didn’t style h2, p, or a everywhere. We only styled them inside
article.
Type selectors for forms
Forms are full of element types that are perfect for type selectors: label, input,
textarea, select, and button.
A very common beginner pattern is: “make all inputs look consistent.” Type selectors shine here.
label {
font-weight: 700;
}
input,
textarea,
select {
border: 2px solid #111;
border-radius: 10px;
padding: 10px 12px;
}
input:focus,
textarea:focus,
select:focus {
outline: 3px solid #0b5fff;
outline-offset: 2px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.form {
font-family: system-ui, ui-monospace, sans-serif;
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
max-width: 760px;
display: grid;
gap: 12px;
}
.row {
display: grid;
gap: 6px;
}
input,
textarea,
select {
font: inherit;
}
button {
border: 0;
background: #111;
color: #fff;
padding: 10px 14px;
border-radius: 10px;
cursor: pointer;
width: fit-content;
}
This is a perfect “type selector use case” because form elements are consistent categories: all inputs should behave similarly.
Type selectors with pseudo-classes and pseudo-elements
You can attach pseudo-classes and pseudo-elements to type selectors.
a:hovermeans “links when hovered”.p::first-lettertargets the first letter of a paragraph.li::markertargets the bullet or number of a list item.
a:hover {
text-decoration-thickness: 4px;
text-underline-offset: 4px;
}
p::first-letter {
font-size: 42px;
font-weight: 700;
padding-right: 6px;
}
li::marker {
color: #0b5fff;
font-weight: 700;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: system-ui, ui-monospace, sans-serif;
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
max-width: 820px;
display: grid;
gap: 12px;
}
p {
margin: 0;
line-height: 1.7;
}
a {
color: #0b5fff;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
}
ul {
margin: 0;
padding-left: 22px;
}
li {
margin: 6px 0;
}
Paragraphs can have fancy first letters. Also, here is a hoverable link.
- Markers can be styled too.
- Blue bullets feel oddly confident.
This is still “type selector territory” because the base selector is a tag name: a, p,
li.
Learn more about :hover in the CSS :hover
Pseudo-Class Interactive Tutorial, and about ::marker in the CSS List Style Interactive Tutorial.
Type selectors with attribute selectors
Attribute selectors are not type selectors, but they combine beautifully with them.
A classic example: target only certain inputs by their type attribute.
inputtargets all inputs.input[type="email"]targets only email inputs.input[type="checkbox"]targets only checkboxes.
input[type="email"] {
border-color: #0b5fff;
}
input[type="password"] {
border-color: #b10f2e;
}
input[type="checkbox"] {
accent-color: #0b5fff;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: system-ui, ui-monospace, sans-serif;
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
max-width: 820px;
display: grid;
gap: 12px;
}
.row {
display: grid;
gap: 6px;
}
input {
font: inherit;
border: 2px solid #111;
border-radius: 10px;
padding: 10px 12px;
}
.small-row {
display: flex;
align-items: center;
gap: 10px;
}
label {
font-weight: 700;
}
Think of this as: start with the element type (input), then filter it down using attributes.
Learn more about attribute selectors in the CSS Attribute Selector Interactive Tutorial.
Specificity and why type selectors are lightweight
CSS decides which rule wins using specificity (and also source order).
Type selectors have low specificity. That’s usually a good thing, because it keeps your CSS flexible.
phas lower specificity than.note.phas lower specificity than#intro.article pis still “type selector level”, just scoped.
This often results in a healthy pattern:
- Use type selectors for base styles.
- Use classes for components and variations.
- Use IDs rarely (mostly for anchors and JS hooks).
p {
color: #0b5fff;
}
.note {
color: #b10f2e;
}
#special {
color: #111;
font-weight: 700;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
font-family: system-ui, ui-monospace, sans-serif;
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
max-width: 760px;
display: grid;
gap: 10px;
}
p {
margin: 0;
line-height: 1.6;
padding: 10px 12px;
border-radius: 12px;
background: #f2f2f2;
}
Just a paragraph. It follows the p rule.
This one has a class, so it can override the p rule.
This one has an ID, which is even stronger.
That’s not “because IDs are better.” It’s simply how the rules are designed. Most modern CSS prefers classes for styling because they’re reusable and easier to manage.
Learn more about specificity in the CSS Specificity Interactive Tutorial.
CSS type selector not working
If your type selector feels like it’s being ignored, it’s usually one of these reasons:
Check you targeted the right element
headertargets<header>, not a class namedheader..headertargets a class, not the element type.#headertargets an ID, not the element type.
Check for more specific rules
- A class selector like
.card pcan overridep. - An ID selector like
#content pcan overridep. - Inline styles can override almost everything.
Check source order
If two selectors have the same specificity, the one that appears later usually wins. This is part of the CSS cascade.
Learn more in the CSS Cascade Interactive Tutorial.
Check for resets or component styles
Some CSS frameworks apply base styles that may conflict with your type selectors. It’s normal. Just make your selector a bit more specific or scope it to a container.
p {
color: #0b5fff;
}
.card p {
color: #b10f2e;
}
.card p {
color: #b10f2e;
}
p {
color: #0b5fff;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
font-family: system-ui, ui-monospace, sans-serif;
max-width: 860px;
display: grid;
gap: 14px;
}
.card,
.plain {
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
}
p {
margin: 0;
line-height: 1.6;
}
Plain area: just a paragraph.
Card area: paragraph inside .card.
Try the third snippet: it has the same two selectors, but reversed order. That’s a very common “wait, why did it change?” moment.
Best practices for type selectors
Use type selectors for base styles
Great targets for base styling:
bodyfor font and general colorsafor default link stylingbuttonfor basic button behaviorimgfor responsive defaults likemax-width: 100%
Scope when you can
Instead of styling p everywhere, style .article p or article p. This avoids
affecting things like footers, sidebars, modals, and random widgets.
Avoid styling rare elements globally
Some elements appear in unexpected places (especially inside third-party embeds). If you globally style something
like svg or input, it can have surprising side effects. Prefer scoping to a container when
possible.
When you want zero specificity use :where
This is a pro-tip: :where() gives the selector zero
specificity, which makes it very easy to override later.
Example idea: :where(article) p behaves like “style paragraphs in articles” but stays lightweight.
:where(article) p {
color: #0b5fff;
}
:where(article) p {
color: #0b5fff;
}
article p.note {
color: #b10f2e;
}
article p {
color: #0b5fff;
}
article p.note {
color: #b10f2e;
}
*,
::before,
::after {
box-sizing: border-box;
}
.layout {
font-family: system-ui, ui-monospace, sans-serif;
display: grid;
gap: 14px;
max-width: 860px;
}
article {
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
}
p {
margin: 0;
line-height: 1.6;
padding: 10px 12px;
border-radius: 12px;
background: #f2f2f2;
}
.note {
background: #fff2c2;
}
Normal article paragraph.
Article paragraph with a class.
The key idea is not “you must use :where().” It’s: type selectors are naturally lightweight, and
:where() can make them even easier to override when building scalable CSS.
Learn more in the CSS :is() and :where() Pseudo-Classes Interactive Tutorial.
Wrap up
CSS type selectors are the simplest selectors: they target elements by tag name. They’re perfect for:
- Base typography and default element styling
- Consistent form control styles
- Scoped styling like
article pornav a
Just remember the golden rule: type selectors are powerful because they match a lot of elements. When you want precision, combine them with structure (descendant/child) or with classes.
