Filter posts by tag "internship" in GROQ query

12 replies
Last updated: Nov 29, 2025
Hello, Im trying to understans GROQ and need help understanding what to do next. I want to in post filter all tags with the string internship and let them show when pushing the button on the navbar. This is my code.

🙏
import { useEffect, useState } from "react";
import sanityClient from "../../client.js";
import { Link, useLocation } from "react-router-dom";
import styles from "./allPosts.module.scss";
import { useMousePosition } from "../Animation/useMousePosition"



export default function AllPosts() {
    const [allPostsData, setAllPosts] = useState(null);
    const position = useMousePosition();
    const location = useLocation()
    console.log(location)

    useEffect(() => {
        sanityClient
        .fetch(
            `*[_type == "post" ]{
                title,
                slug,
                tags,
                mainImage{
                    asset ->{
                        _id,
                        url,
                        alt,
                    }
                }
            }`
        )
        .then((data) => setAllPosts(data))
        .catch(console.error)
    }, [])
    return (
        <div className={styles.flex}>
            <div className={styles.landingTitle}>
            {position.x}:{position.y}
                <h1 className={styles.verticalText}>Work</h1>
            </div>

            <div className={styles.wrapper}>
                {allPostsData &&
                    allPostsData.map((post, index) => (
                        <Link to={'/' + post.slug.current} key={post.slug.current}>
                            <span key={index}>
                                <img className={styles.heroImage} 
                                    src={post.mainImage.asset.url} 
                                    caption={post.mainImage.caption} 
                                    alt={post.mainImage.alt}
                                />

                                <h2 className={styles.title}>
                                    {post.title}
                                </h2>
                            </span>
                        </Link>

                    ))}

            </div>
        </div>
    )
}

AI Update

Looking at your code, I can see you want to filter posts by tags containing the string "internship". The key GROQ operator you need is the in operator to check if a value exists in an array.

Here's how to modify your query:

Basic filter for exact match:

sanityClient
  .fetch(
    `*[_type == "post" && "internship" in tags]{
      title,
      slug,
      tags,
      mainImage{
        asset ->{
          _id,
          url,
          alt,
        }
      }
    }`
  )

This uses the in operator which checks if the string "internship" exists anywhere in your tags array.

For a button-triggered filter, add state management:

export default function AllPosts() {
    const [allPostsData, setAllPosts] = useState(null);
    const [showInternships, setShowInternships] = useState(false);
    const position = useMousePosition();
    const location = useLocation();

    useEffect(() => {
        // Build query based on filter state
        const filter = showInternships 
            ? `*[_type == "post" && "internship" in tags]`
            : `*[_type == "post"]`;
        
        sanityClient
            .fetch(
                `${filter}{
                    title,
                    slug,
                    tags,
                    mainImage{
                        asset ->{
                            _id,
                            url,
                            alt,
                        }
                    }
                }`
            )
            .then((data) => setAllPosts(data))
            .catch(console.error);
    }, [showInternships]); // Re-fetch when filter changes

    return (
        <div className={styles.flex}>
            <div className={styles.landingTitle}>
                {position.x}:{position.y}
                <h1 className={styles.verticalText}>Work</h1>
                
                {/* Add filter button */}
                <button onClick={() => setShowInternships(!showInternships)}>
                    {showInternships ? "Show All Posts" : "Show Internships Only"}
                </button>
            </div>

            <div className={styles.wrapper}>
                {allPostsData &&
                    allPostsData.map((post, index) => (
                        <Link to={'/' + post.slug.current} key={post.slug.current}>
                            <span>
                                <img className={styles.heroImage} 
                                    src={post.mainImage.asset.url} 
                                    alt={post.mainImage.alt}
                                />
                                <h2 className={styles.title}>
                                    {post.title}
                                </h2>
                            </span>
                        </Link>
                    ))}
            </div>
        </div>
    );
}

Important notes:

  1. The "internship" in tags syntax checks if the exact string "internship" exists in your tags array
  2. If your tags are objects (like {title: "internship"}), you'd need: "internship" in tags[]->title or similar depending on your schema
  3. The in operator returns true when it finds a match, false if no match, and null if the array contains null values

For partial matching (if you need to match tags that contain "internship" as part of a longer string), you'd use the match operator instead:

`*[_type == "post" && tags match "*internship*"]`

This would match tags like "summer-internship", "internship-2024", etc.

Show original thread
12 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?